Mixins - cpeosphoros/30log-plus GitHub Wiki
30log provides a basic support for mixins. This is a powerful concept that can be used to share the same functionality across different classes, especially when they are unrelated.
30log implements mixins as tables containing a set of functions prototyped as
class methods. A mixin is included in a class using class:with().
-- A simple Geometry mixin
local Geometry = {
getArea = function(self) return self.width * self.height end
}
-- Let us define two unrelated classes
local Window = class ("Window", {width = 480, height = 250})
local Button = class ("Button", {width = 100, height = 50, onClick = false})
-- From *30log*:
-- Include the "Geometry" mixin in Window and Button classes
-- Window:with(Geometry)
-- Button:with(Geometry)
-- With 30log-plus, adding mixins after a class has been created is deprecated.
-- Although it works with the current develop branch, that may change at
-- anytime, in order to provide stronger class identity and initialization. Use
-- this, instead:
GWindow = Window:extend():with(Geometry)
GButton = Button:extend():with(Geometry)
-- Let us define instances from those classes
local aWindow = GWindow()
local aButton = GButton()
-- Instances can use functionalities brought by Geometry mixin.
print(aWindow:getArea()) -- outputs 120000
print(aButton:getArea()) -- outputs 5000
Also, note that a mixin cannot be included more than once. Trying to add to a class a mixin which was already included will raise an error.
-- raises an error, since Geometry mixin was already added to class 'GWindow'
BWindow = GWindow:extend():with(Geometry)
The new methods provided by the mixins works as regular methods. Subclasses will inherit them.
Also, the built-in class method :with() can takes a variable number of mixins
or use chaining to include a lot of mixins at once.
MWindow = Window:extend():with(mixin1, mixin2, mixin3,...)
-- same as the previous line
MWindow = Window:extend():with(mixin1):with(mixin2):with(mixin3):with(...)
What if we want to know if a specific mixin was added to a class ? We can use
the buit-in class method :includes(). It returns true when a class or any of
its superclasses includes a specific mixin.
print(GWindow:includes(Geometry)) -- outputs true
print(GButton:includes(Geometry)) -- outputs true
-- Let us create a subclass from GWindow class
local subWindow = GWindow:extend()
print(subWindow:includes(Geometry)) -- still outputs true
Finally, a mixin can be removed from a class via the built-in class method
:without():
NWindow = GWindow:extend()without(Geometry)
print(NWindow:includes(Geometry)) -- outputs false
print(NWindow.getArea) -- outputs nil
Similarly to :with(), :without() can take a variable number or mixins to be
removed from a class at once. Or it can use chaining, too.
MWindow = Window:extend():without(mixin1, mixin2, mixin3,...)
-- same as the previous line
MWindow = Window:extend():without(mixin1):without(mixin2):without(mixin3):without(...)
See also: Mixins Plus