OOP#
Lua has no class keyword. Object orientation is built from
two primitives the operator already has: tables (which hold the
state) and metatables (which intercept reads, writes, and
operator calls). Method-call sugar (obj:method()) and the
__index metamethod give the rest.
For the underlying call surface, see Functions. For the operator-overloading metamethods that fit naturally here, see Operators.
Metatables#
Every table can have a metatable attached with
setmetatable(t, mt). The metatable’s fields are
metamethods, hooks the runtime calls when certain operations
hit the table. The most-used metamethod is __index, which is
consulted when a read misses.
local fallback = {name = "default", port = 80}
local config = {port = 8080}
setmetatable(config, {__index = fallback})
print(config.port) --> 8080 hit on config
print(config.name) --> default miss, looked up in fallback
__index can also be a function; the runtime calls it with
(t, key) and uses the returned value.
The full metamethod set covers reads (__index), writes
(__newindex), arithmetic (__add, __sub, __mul,
__div, __mod, __pow, __unm, __concat),
comparison (__eq, __lt, __le), call (__call),
length (__len), iteration (__pairs), tostring
(__tostring), and garbage collection (__gc).
Objects#
A Lua object is a table whose metatable’s __index points to
a class table of shared methods. The class table is itself an
ordinary table; methods are just functions that take self as
the first argument.
local Point = {}
Point.__index = Point -- methods live here
function Point.new(x, y) -- constructor (called as Point.new)
return setmetatable({x = x, y = y}, Point)
end
function Point:distance(other) -- method (called as p:distance(q))
local dx, dy = self.x - other.x, self.y - other.y
return math.sqrt(dx*dx + dy*dy)
end
local p = Point.new(0, 0)
local q = Point.new(3, 4)
print(p:distance(q)) --> 5.0
Two pieces of sugar are at work. p:distance(q) is
Point.distance(p, q) after __index resolves the method.
function Point:distance(other) is
function Point.distance(self, other) because the colon adds
self automatically.
Inheritance#
Single inheritance is a one-line chain of __index tables.
local Animal = {}
Animal.__index = Animal
function Animal.new(name)
return setmetatable({name = name}, Animal)
end
function Animal:speak() print(self.name .. " makes a sound") end
local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog
function Dog.new(name) return setmetatable({name = name}, Dog) end
function Dog:speak() print(self.name .. " barks") end
local d = Dog.new("rex")
d:speak() --> rex barks
Multiple inheritance is built by giving __index a function
that walks several parent tables.
local function search(k, parents)
for _, p in ipairs(parents) do
local v = p[k]
if v ~= nil then return v end
end
end
local function class(parents)
local c = {}
setmetatable(c, {__index = function(_, k) return search(k, parents) end})
c.__index = c
return c
end
Operator overloading#
Arithmetic, concat, comparison, length, and call all dispatch through metamethods. The runtime checks the metatable of the left operand first, then the right.
local Vec = {}
Vec.__index = Vec
function Vec.new(x, y) return setmetatable({x = x, y = y}, Vec) end
function Vec.__add(a, b) return Vec.new(a.x + b.x, a.y + b.y) end
function Vec.__eq(a, b) return a.x == b.x and a.y == b.y end
function Vec.__tostring(v) return ("(%g, %g)"):format(v.x, v.y) end
local a = Vec.new(1, 2)
local b = Vec.new(3, 4)
print(tostring(a + b)) --> (4, 6)
print(a == Vec.new(1, 2)) --> true
References#
Functions for the call surface methods build on.
Operators for the operator semantics metamethods override.
Data Structures for tables as the underlying object storage.
Patterns for higher-level OOP idioms (classes, mixins, prototypes).