Most Lua codebases (games, plugins, libraries) use this pattern for objects.
Lua has no class keyword. Instead a class is a table of methods, and instances are tables whose metatable has __index pointing at that class. Missing fields (the methods) are found on the class.
The colon syntax wires up self. function Account:deposit(v) defines a function with a hidden first parameter self, and acc:deposit(10) calls Account.deposit(acc, 10). Mixing . and : is the classic bug: acc.deposit(10) passes 10 as self.
A typical constructor is function Class.new(...) that creates a table, sets the metatable and initialises fields. Setting Class.__index = Class lets the class serve as its own metatable.
Inheritance chains lookups: make the subclass's metatable index the parent class (setmetatable(Sub, {__index = Base})). A missing method is searched in the instance, then the subclass, then the base. Call the parent's method explicitly with Base.method(self, ...); there is no super.
Privacy is a convention (an underscore prefix) unless you use closures instead of tables for state. Many projects use a small class library (middleclass, classic), but they are thin wrappers over exactly this mechanism, so it pays to understand it directly.
Example
local Account = {}
Account.__index = Account
function Account.new(owner, balance)
return setmetatable({owner = owner, balance = balance or 0}, Account)
end
function Account:deposit(v) self.balance = self.balance + v end
function Account:describe() return self.owner .. ": " .. self.balance end
local Savings = setmetatable({}, {__index = Account})
Savings.__index = Savings
function Savings.new(owner, balance, rate)
local self = Account.new(owner, balance)
self.rate = rate
return setmetatable(self, Savings)
end
function Savings:add_interest() self:deposit(self.balance * self.rate) end
function Savings:describe()
return Account.describe(self) .. " @" .. self.rate -- call "super"
end
local s = Savings.new("ana", 100, 0.05)
s:add_interest()
print(s:describe()) --> ana: 105.0 @0.05
print(getmetatable(s) == Savings) --> trueRemember
- A class is a method table used as the instances'
__index obj:m(x)isobj.m(obj, x); define methods with:to getself- Inheritance = the subclass table's own
__indexpoints at the base
Watch out for
- Calling a method with a dot (
obj.m()), soselfis missing or wrong.