-
Notifications
You must be signed in to change notification settings - Fork 0
Classes and Inheritance in Lua
The following code snippet shows how classes can be emulated in Lua:
local Point2D = {} -- define `Point2D` as a new "class"
Point2D.__index = Point2D -- allow "instances" to access the methods of the class
function Point2D.new(class, x, y) -- constructor for `Point2D` (note the first parameter, `class`, referring to the class itself)
local self = setmetatable({}, class) -- create a new "instance" of the class, called `self`
self._x = x or 0 -- set the fields of the instance
self._y = y or 0 -- "private" variables are often indicated using a preceding `_`
return self -- remember to return the new instance
end
function Point2D:getX() -- instance method (note the use of `:`)
return self._x
end
function Point2D:getY() -- instance method (note the use of `:`)
return self._y
end
To make new instances of Point2D
, all you have to do is call Point2D:new(x, y)
, as the following snippet demonstrates:
local point = Point2D:new(10, 20)
print( point:getX(), point:getY() ) -- prints: 10 20
To use a class as a module, simply return it from it's file. You can then use
local Point2D = require "path.to.Point2D"
to import/include it in other files.
A small note on the use of
:
in LuaThe syntax
function Point2D:getX() -- ... endimplicitly adds
self
as the first parameter, i.e. it's shorthand forfunction Point2D.getX(self) -- ... endSimilarly, the syntax
point:getX()implicitly passes
point
as the first argument, i.e. it's shorthand forpoint.getX(point)
Inheritance can also be emulated, as the following snippet demonstrates:
local Position = {} -- define `Position` as a new class
Position.__index = Position -- allow instances to access the class methods
setmetatable(Position, {__index = Point2D}) -- make `Position` "inherit" from `Point2D`
function Position:move(dx, dy) -- instance method (note the use of `:`)
self._x = self._x + (dx or 0)
self._y = self._y + (dy or 0)
end
Notice how we haven't defined a new constructor for
Position
? When making classes as described here, subclasses automatically inherit the constructor of their parent class, unless a custom constructor is provided.
We can create new instances of Position
using Position:new(x, y)
, as shown in the example below:
local pos = Position:new(10, 20)
print( pos:getX(), pos:getY() ) -- prints: 10 20
pos:move(5, -5)
print( pos:getX(), pos:getY() ) -- prints: 15 15
In the example above we didn't need to define a new constructor, but sometimes we do. This is done simply be defining a new constructor on the subclass. Doing so will "overshadow" the parent constructor, however it's often useful to still be able to call the parent constructor from within the subclass constructor.
The following snippet shows how this can be achieved in Lua:
local Point3D = {} -- define `Point3D` as a new class
Point3D.__index = Point3D -- allow instances to access the methods of the class
setmetatable(Point3D, {__index = Point2D}) -- make `Point3D` inherit from `Point2D`
function Point3D.new(class, x, y, z) -- constructor for `Point3D` (note the first parameter, `class`, referring to the class itself)
local self = Point2D:new(x, y) -- invoke the parent constructor
setmetatable(self, class) -- make it an instance of this class
self._z = z or 0 -- add the remaining fields
return self -- remember to return the new instance
end
function Point3D:getZ() -- instance method (note the use of `:`)
return self._z
end
The same technique can be used to override methods.
We can create new instances of Point3D
using Point3D:new(x, y, z)
, as shown in the example below:
local p3 = Point3D:new(10, 20, 30)
print( p3:getX(), p3:getY(), p3:getZ() ) -- prints: 10 20 30
The only real limitation of emulating classes in Lua is the lack of method overloading, which is an unfortunate a natural consequence of Lua being a dynamically typed language.
Methods to overcome this limitation does exist, but these are both to complex and to context specific to be covered in this tutorial.