Bienvenidos sean a este post, es una practica comun para las librerias definir sus propios campos en metatablas, hasta ahora todos los metametodos que hemos visto son para el nucleo de Lua, es la maquina virtual quien detecta cuales valores envueltos tienen metatablas y cual de estas metatablas definen metametodos para tal operacion, sin embargo porque las metatablas son tablas regulares, estas pueden ser usadas por cualquiera, un tipico ejemplo es la funcion tostring, como vimos anteriormente esta funcion representa tablas en un formato bastante simple:
> print({})
table: 0x8d2768
>
Nota: La funcion print siempre llama a tostring para dar formato a su salida.
Cuando formateamos cualquier valor, tostring primero verifica si el valor tiene un metatmetodo __tostring, en este caso tostring llama al metametodo para realizar su trabajo, pasando el objeto como su argumento, sea lo que el metametodo devuelva es el resultado de tostring, siguiendo con nuestro ejemplo de conjuntos donde ya hemos definido una funcion para representar a las cadenas, Conjunto.acadena, ahora solo nos falta crear el campo __tostring en la metatabla:
mt.__tostring = Conjunto.acadena
Despues de este cambio siempre que llamemos a print como un conjunto como su argumento, print llama a tostring que a su vez llama Conjunto.acadena, veamos el siguiente ejemplo:
> s1 = Conjunto.nuevo{10, 4, 5}
> print(s1)
{ 4, 5, 10 }
>
Las funciones setmetatable y getmetatable tambien usan un metacampo, en este caso para proteger metatablas, supongamos que queremos proteger nuestros conjuntos para que ningun usuario pueda ver o cambiar sus metatablas, si seteamos un campo __metatable en la metatabla, getmetatable devolvera el valor de este campo, mientras que setmetatable devolvera un error, agreguemos el siguiente codigo a nuestro codigo:
mt.__metatable = "no es de tu incumbencia"
Si lo verificamos de la siguiente manera obtendremos esta salida:
> s1 = Conjunto.nuevo{}
> print(getmetatable(s1))
no es de tu incumbencia
> setmetatable(s1, {})
stdin:1: cannot change a protected metatable
En este caso observamos las dos conductas que mencionamos, la primera al intentar ver la metatabla de s1 nos devolvio el mensaje que le seteamos, en el segundo caso cuando intentamos modificarlo nos informa que la metatabla esta protegida, veamos el nuevo codigo final:
metamtd01.lua
Conjunto = {}
local mt = {}
function Conjunto.nuevo(l)
local conjunto = {}
setmetatable(conjunto, mt)
for _, v in ipairs(l) do conjunto[v] = true end
return conjunto
end
function Conjunto.union(a, b)
local res = Conjunto.nuevo{}
if getmetatable(a)~=mt or getmetatable(b)~=b then
error("Intentaste 'agregar' un conjunto con un valor no-conjunto", 2)
end
for k in pairs(a) do res[k] = true end
for k in pairs(b) do res[k] = true end
return res
end
function Conjunto.interseccion(a, b)
local res = Conjunto.nuevo{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end
function Conjunto.acadena(set)
local l = {}
for e in pairs(set) do
l[#l + 1] = e
end
return "{ " .. table.concat(l,", ") .. " }"
end
function Conjunto.imprimir(c)
print(Conjunto.acadena(c))
end
mt.__add = Conjunto.union
mt.__mul = Conjunto.interseccion
mt.__le = function(a, b)
for k in pairs(a) do
if not b[k] then return false end
end
return true
end
mt.__lt = function(a, b)
return a <= b and not(b <= a)
end
mt.__eq = function(a, b)
return a <= b and b <= a
end
mt.__tostring = Conjunto.acadena
mt.__metatable = "no es de tu incumbencia"
En resumen, hoy hemos visto algunas de las funciones internas que propias de las metatablas, cuales son, como se utilizan, cuales son los beneficios que obtenemos, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar
Es para mantenimiento del sitio, gracias!
$1.50