Lua Metatables
A metatable is a table that holds extra behaviour for another table. Attaching one can teach an operator like + how to work with that table.
Adding two vectors the manual way
Without a metatable, each field must be added by hand into a new table. The printed fields show the sums this manual work produces.
local a = {x = 3, y = 4}
local b = {x = 1, y = 2}
local c = {x = a.x + b.x, y = a.y + b.y}
print(c.x, c.y)__add teaches + to add vectors
Both vectors share one metatable whose __add field builds the summed vector. The same sums now come from a single + sign.
local mt = {
__add = function(a, b)
return {x = a.x + b.x, y = a.y + b.y}
end
}
local a = setmetatable({x = 3, y = 4}, mt)
local b = setmetatable({x = 1, y = 2}, mt)
local c = a + b
print(c.x, c.y)__tostring gives print a string to show
Printing a table value is allowed here only because __tostring replaces the usual table address with a string. print shows exactly the string that field returns.
local mt = {
__tostring = function(p)
return "(" .. p.x .. ", " .. p.y .. ")"
end
}
local point = setmetatable({x = 3, y = 4}, mt)
print(point)Example
local mt = {}
mt.__add = function(a, b)
return setmetatable({amount = a.amount + b.amount}, mt)
end
mt.__tostring = function(m)
return string.format("%.2f USD", m.amount)
end
local a = setmetatable({amount = 12.5}, mt)
local b = setmetatable({amount = 7.25}, mt)
local total = a + b
print(total)Key points
- Metatable: a table that holds extra behaviour for another table.
- setmetatable(): attaches a metatable to a table and returns that table.
- __add: a field in the metatable that tells Lua what + should do with the table.
- __tostring: a field in the metatable that tells print what string to show for the table.
- Plain fields: a table with a metatable still stores and reads its own fields in the normal way.
In this example, a money table carries one field named amount. Its metatable adds two amounts with __add and gives the total the same metatable. Its __tostring field formats the amount with string.format("%.2f USD"), so printing the total shows 19.75 USD.
Note
most tables in this course have no metatable, so + and print keep their plain meanings for them.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does setmetatable(t, mt) do?