Bienvenidos sean a este post, hoy continuaremos con lo visto en los posts anteriores pero para este caso transformaremos a nuestro nuevo tipo en un objeto, asi podemos operarlo en sus instancias usando la sintaxis orientada a objetos usual:
a = array.nuevo(1000)
print(a:tamano()) -- Devuelve 1000
a.set(10, true)
print(a:get(10)) -- Devuelve true
Recuerden que en Lua usar esta expresion:
a:tamano()
Es equivalente a:
a.tamano(a)
Por lo tanto tenemos que arreglar que la expresion a.tamano devuelva nuestra funcion getsize, el mecanismo clave aca es el metametodo __index, para las tablas este metametodo es llamado cuando Lua no puede encontrar un valor para la clave informada, para userdatum es llamado en cada acceso porque userdatum no posee ninguna clave, asumamos que ejecutamos el siguiente codigo:
local metaarray = getmetatable(array.nuevo(1))
metaarray.__index = metaarray
metaarray.set = array.set
metaarray.get = array.get
metaarray.tamano = array.tamano
Primero creamos un array para conseguir su metatabla la cual asignamos a metaarray, no podemos configurar la metatabla de un userdatum desde Lua pero podemos conseguirla sin restricciones, luego seteamos a metaarray.__index con metaarray, cuando evaluamos a.tamano Lua no puede encontrar la clave «tamano» en el objeto a porque el objeto es un userdatum, por lo tanto Lua intenta conseguir este dato del campo __index de la metatabla de a, la cual es metaaray en si misma, esto da como resultado que metaarray.tamano equivale a array.tamano asi a.tamano(a) resulta en array.tamano(a) que es lo que buscabamaos.
Por supuesto que esto lo podriamos escribir en C, lo podriamos hacer inclusive mejor, como ahora los arrays son objetos con sus propias operaciones, no tenemos necesidad de tener mas estas operaciones en la tabla array, la unica funcion que nuestra libreria aun tiene que exportar es nuevo para crear nuevos arrays, todas las otras operaciones vienen solo como metodos, el codigo C puede registrarlas directamente como tales. Las operaciones setarray, getarray y getsize no cambian desde el enfoque anterior, lo unico que cambiaremos es como registrarlas es decir, que tenemos que cambiar la funcion que abre la libreria, primero necesitamos dos listas de funciones separadas, una para funciones comunes y otra para metodos:
static const struct luaL_Reg arraylib_f [] = {
{"nuevo", nuevoarray},
{NULL, NULL}
};
static const struct luaL_Reg arraylib_m [] = {
{"set", setarray},
{"get", getarray},
{"tamano", getsize},
{NULL, NULL}
};
La nueva version de la funcion de apertura luaopen_array tiene que crear la metatabla, asignarla a su propio campo __index, registrar todos los metodos ahi, crear y llenar la tabla array:
int luaopen_array(lua_State *L)
{
luaL_newmetatable(L, "LuaBook.array");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_register(L, NULL, arraylib_m);
luaL_register(L, "array", arralib_f);
return 1;
}
Aqui usamos otra caracteristica de luaL_register, en la primer llamada cuando pasamos NULL como nombre de libreria, el metodo no crea ninguna tabla para empaquetar las funciones en su lugar asume que la tabla paquete esta en la parte superior de la pila, en este ejemplo la tabla paquete es la metatabla en si mismo la cual es compartida habitualmente: crea una nueva tabla con el nombre informado (array) y registra las funciones informadas ahi (solo nuevo en este caso), como para ir finalizando agregaremos un metodo __tostring para nuestro nuevo tipo asi que print(a) imprima el array ademas el tamaño del array entre parentesis, algo como array(1000), la funcion en si es la siguiente:
int array2string(lua_State *L)
{
NumArray *a = checkarray(L);
lua_pushfstring(L, "array(%d)", a->tamano);
return 1;
}
En este caso la llamada lua_pushfstring no solamente formatea la cadena sino que tambien la deja en la parte superior de la pila, nuestro ultimo paso es agregar este nuevo metodo a la lista de arraylist_m para incluirla en la tabla de objetos del array, debemos modificar el codigo de la siguiente forma:
static const struct luaL_Reg arraylib_m [] = {
{"__tostring", array2string},
{"set", setarray},
{"get", getarray},
{"tamano", getsize},
{NULL, NULL}
};
En resumen, hoy hemos transformado nuestro nuevo tipo en objeto, hemos visto como darle las propiedades y metodos propios de los objetos, como configurar su conducta para esto, hemos visto como con simples modificaciones se puede hacer, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo
Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.


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