Anuncios

Bienvenidos sean a este post, continuemos con el tema comenzado en los posts anteriores, como los objetos no son primitivos en Lua hay varias maneras de hacer una programacion orientada a objetos: el enfoque que hemos visto usando el metametodo index, quiza sea la mejor combinacion de simplicidad, performance y flexibilidad, sin embargo hay otras implementaciones las cuales podrian ser mas apropiadas para algunos casos particulares, aqui veremos una implementacion alternativa que permite multiples herencias en Lua.

Anuncios

La clave para esta implementacion es el uso de una funcion para el metacampo __index, cuando una metatabla de una tabla tiene una funcion en el campo __index, Lua llamara a esta funcion cuando no pueda encontrar una clave en la tabla original, luego __index puede buscar por un clave en cuantos origenes quiera.

La herencia multiple significa que una clase puede tener mas de una superclase por lo tanto no podemos usar un metodo de clase para crear subclases, veamos el siguiente codigo:

Anuncios
local function buscar(k, lista)
	for i = 1, #lista do
		local v = lista[i][v]
		if v then return v end
	end
end

function crearClase(...)
	local c = {}
	local padres = {...}

	setmetatable(c, {__index = function(t,k)
		return buscar(k, padres)
	end})

	c.__index = c

	function c:nuevo(o)
		o = o or {}
		setmetatable(o, c)
		return o
	end

	return c
end

La primera funcion, buscar, busca por un objeto dentro de la lista de padres, una vez encontrado lo devuelve, nuestra siguiente funcion es crearClase la cual tiene como argumento las superclases de la nueva clase, setea su metatabla con un metametodo __index que hace las multiples herencias, a pesar de la multiple herencia cada instancia de objeto aun pertenece a una clase unica, donde buscara por todos sus modulos por lo tanto la relacion entre clases e instancias se seguiran manteniendo como en la herencia simple porque una clase no puede ser la metatabla para sus instancias y para sus subclases al mismo tiempo, en el codigo mantenemos la clase como la metatabla para sus instancias y crea otra tabla para ser la metatabla de la clase.

Anuncios

Vamos a ver como funcion crearClase con un pequeño ejemplo, asumamos que nuestra clase previa Cuenta y otra clase llamada Nombrada con solo dos metodos: setnombre y getnombre:

Nombrado = {}

function Nombrado:getnombre()
	return self.nombre
end

function Nombrado:setnombre(n)
	self.nombre = n
end
Anuncios

Para crear una nueva clase llamada CuentaNombrada que es una subclase de Cuenta y Nombrado con simplemente llamar a crearClase:

CuentaNombrada = crearClase(Cuenta, Nombrado)

Para crear y usar instancias lo hacemos de la forma usual:

cuenta = CuentaNombrada:nuevo{ nombre = "Martin" }
print(cuenta:getnombre())		// Devuelve Martin
Anuncios

Veamos como funciona este declaracion, Lua no puede encontrar el campo getnombre en cuenta, busca en el campo __index de la metatabla de cuenta, la cual es CuentaNombrada pero CuentaNombrada tampoco provee un campo getnombre asi que Lua busca a __index de la metatabla de CuentaNombrada como este campo contiene una funcion Lua la llama, esta funcion busca por getnombre primero en Cuenta, como no tiene exito procede a hacerlo en Nombrado donde encuentra un valor no nil el cual es el resultado final de buscar, por supuesto debido a la complejidad subyacente de esta busqueda la performance de multiples herencias no es la misma a una herencia simple, una manera simple de mejorar esta performance es copiar metodos heredados dentro de las subclases, usando esta tecnica el metametodo index para las clases seria algo como esto:

Anuncios
setmetatable(c, {__index = function(t, k)
	local v = buscar(k, padres)
	t[k] = v
	return v
end})

Con este truco los accesos a metodos heredados son tan rapidos como los metodos locales (excepto por el primer acceso), la contra es que sera dificil cambiar la definicion de los metodos una vez que el sistema este corriendo porque estos cambios no se propagan hacia abajo en la cadena de jerarquia.

Anuncios

En resumen, hoy hemos visto herencia multiple, para que sirve, como se crea, como nos beneficia, y como optimizarla, 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.

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.00