-
Notifications
You must be signed in to change notification settings - Fork 53
Subclasses
A subclass can be derived from a class using a reserved method named extend
.
Similarly to class()
, this method also takes an optional argument name
and an optional argument params
implemented as a table with named keys.
The new subclass inherits its superclass attributes and methods.
local Window = class ("Window", { width = 150, height = 100})
local Frame = Window:extend("Frame", { color = "black" })
local appFrame = Frame()
print(appFrame.width, appFrame.height, appFrame.color) -- outputs 150, 100, "black"
A subclass has an attribute named super
which points to its superclass.
print(Frame.super) -- outputs "class 'Window' (table: 0x0002ceb8)"
A subclass can have its own copies of its superclass attributes and method. Therefore, it can redefine them without affecting the superclass itself. However, a subclass still has free access to his superclass attributes and methods via super
.
-- A base class "Window"
local Window = class ("Window", {x = 10, y = 10, width = 150, height = 100})
function Window:init(x, y, width, height)
Window.set(self, x, y, width, height)
end
function Window:set(x, y, w, h)
self.x, self.y, self.width, self.height = x, y, w, h
end
-- a "Frame" subclass
local Frame = Window:extend({color = 'black'})
function Frame:init(x, y, width, height, color)
-- Calling the superclass constructor
Frame.super.init(self, x, y, width, height)
-- Setting the extra class member
self.color = color
end
-- Redefining the set() method
function Frame:set(x,y)
self.x = x - self.width/2
self.y = y - self.height/2
end
-- An appFrame from "Frame" class
local appFrame = Frame(100,100,800,600,'red')
print(appFrame.x, appFrame.y) -- outputs 100, 100
-- Calls the new set() method
appFrame:set(400,400)
print(appFrame.x, appFrame.y) -- outputs 0, 100
-- Calls the old set() method in the superclass "Window"
appFrame.super.set(appFrame,400,300)
print(appFrame.x, appFrame.y) -- outputs 400, 300
Also, bear in mind classes are metatables of their subclasses.
local aClass = class("aClass")
local aSubClass= aClass:extend()
print(getmetatable(aSubClass)) -- outputs "class 'aClass' (table: 0x0002cee8)"
This built-in function returns true when the class from which the method is called is a superclass of a given class.
local aClass = class("aClass")
local aSubClass= aClass:extend()
print(aClass:classOf(aSubClass)) -- outputs true
It also returns true even if the given class is not a direct subclass, as long as they are related.
local classLevelOne = class("classLevelOne")
local classLevelTwo = classLevelOne:extend("classLevelTwo")
local classLevelThree = classLevelTwo:extend("classLevelThree")
print(classLevelOne:classOf(classLevelTwo)) -- outputs true
print(classLevelOne:classOf(classLevelThree)) -- also outputs true
This built-in function returns true when the class from which the method is called is a subclass of a given class.
local aClass = class("aClass")
local aSubClass= aClass:extend()
print(aSubClass:subclassOf(aClass)) -- outputs true
It also returns true even if the given class is not a direct superclass, as long as they are related.
local classLevelOne = class("classLevelOne")
local classLevelTwo = classLevelOne:extend("classLevelTwo")
local classLevelThree = classLevelTwo:extend("classLevelThree")
print(classLevelThree:subclassOf(classLevelTwo)) -- outputs true
print(classLevelThree:subclassOf(classLevelOne)) -- also outputs true
This is another built-in class function which returns the list of all subclasses from a given class. For example, let us consider the following hierarchy:
local GraphicalObject = class('GraphicalObject')
local Rect = GraphicalObject:extend('Rect')
local Window = Rect:extend('Window')
local Button = Rect:extend('Button')
The GraphicalObject
class has three subclasses: Rect
, Window
and Button
.
The Rect
class has two subclasses: Window
and Button
.
We can list them using :subclasses()
:
local subclasses = GraphicalObject:subclasses()
for _, subclass in ipairs(subclasses) do print(subclass) end -- outputs 'Rect', 'Window' and 'Button'.
local subclasses = Rect:subclasses()
for _, subclass in ipairs(subclasses) do print(subclass) end -- outputs 'Window' and 'Button'.
Eventually, :subclasses()
can take an optional function argument filter
, plus a vararg to be passed as arguments to the function filter
. This filter should be implemented according to the following prototype:
local filter(subclass, ...)
if someCondition then return true end
end
This filter function will be applied to all the subclasses of a given class. When this filter evaluates to false
or nil
, the subclass will not be included in the returned collection.
For example, we can use this filter only the direct subclasses of GraphicalObject
class.
local direct_subclasses = GraphicalObject:subclasses(function(s)
return s.super == GraphicalObject
end)
for _, subclass in ipairs(direct_subclasses) do print(subclass) end -- outputs 'Rect'.
This built-in class function returns the list of all instances from a given class. For example, let us consider the following hierarchy:
local GraphicalObject = class('GraphicalObject')
local Rect = GraphicalObject:extend('Rect')
local Window = Rect:extend('Window')
local Button = Rect:extend('Button')
local aRect = Rect()
local aWindow = Window()
local aButton = Button()
The Rect
class has three instances: aRect
, aWindow
and aButton
.
The Window
class has a single instance: aWindow
The Button
class has a single instance: aButton
This can be shown in Lua code:
local instances = Rect:instances()
for _, instance in ipairs(instances) do print(instance) end -- outputs `aRect `, `aWindow` and `aButton`.
local instances = Window:instances()
for _, instance in ipairs(instances) do print(instance) end -- outputs `aWindow`.
local instances = Button:instances()
for _, instance in ipairs(instances) do print(instance) end -- outputs `aButton`.
Similarly to :subclasses()
, :instances()
takes an optional filter function prototyped as follows:
local filter(instance, ...)
if someCondition then return true end
end
This filter function will be applied to all the instances of a given class. When this filter evaluates to false
or nil
, the instance will not be included in the returned collection.
For example, we can use this to filter only the direct instances of Rect
class.
local direct_instances = Rect:instances(function(s)
return s.class == Rect
end)
for _, instance in ipairs(direct_instances) do print(instance) end -- outputs 'aRect'.