Inheritance
Prerequisites: Object-oriented programming
Inheritance is a chain of __index lookups: an instance looks in its
class, the class looks in its parent class.
local Shape = {}
Shape.__index = Shape
function Shape.new(name)
return setmetatable({name = name}, Shape)
end
function Shape:area() return 0 end
function Shape:describe()
return string.format("%s with area %.2f", self.name, self:area())
end
local Circle = setmetatable({}, {__index = Shape})
Circle.__index = Circle
function Circle.new(radius)
local self = Shape.new("Circle")
self.radius = radius
return setmetatable(self, Circle)
end
function Circle:area() return math.pi * self.radius ^ 2 end
local Square = setmetatable({}, {__index = Shape})
Square.__index = Square
function Square.new(side)
local self = setmetatable(Shape.new("Square"), Square)
self.side = side
return self
end
function Square:area() return self.side * self.side end
for _, s in ipairs({Circle.new(1), Square.new(3), Shape.new("Blob")}) do
print(s:describe())
end
Circle with area 3.14
Square with area 9.00
Blob with area 0.00
setmetatable(Circle, {__index = Shape})makesCirclefall back toShapefor methods it doesn't define, likedescribe.- The child constructor calls the parent's constructor, then switches the metatable to the child class.
self:area()indescribecalls the child'sarea— that's polymorphism.
A small class helper
Projects usually wrap this pattern in a helper (or use a library like middleclass or classic):
local function class(parent)
local c = {}
c.__index = c
if parent then setmetatable(c, {__index = parent}) end
c.new = function(...)
local obj = setmetatable({}, c)
if obj.init then obj:init(...) end
return obj
end
return c
end
local Animal = class()
function Animal:init(name) self.name = name end
function Animal:speak() return self.name .. " makes a sound" end
local Dog = class(Animal)
function Dog:speak() return self.name .. " barks" end
print(Animal.new("Generic"):speak())
print(Dog.new("Rex"):speak())
Generic makes a sound
Rex barks
Dog inherits init from Animal and overrides speak. To call the
parent's version from a child, call it explicitly:
Animal.speak(self).