setmetatable
setmetatable(table, metatable) Assigns a metatable to a table. The metamethods inside the metatable control how the table behaves when you use operators, index it, or call it like a function.
Signature
setmetatable(table, metatable)
table is the table you want to modify. metatable is the table to assign — pass nil to remove an existing metatable.
The function returns the table argument, so you can set the metatable and keep working in one expression.
Parameters
| Parameter | Type | Description |
|---|---|---|
table | table | The table to attach the metatable to. In Lua 5.4+, this must be an actual table — setting a metatable on a non-table value like a number or string raises an error. |
metatable | table or nil | The metatable to attach. Use nil to remove the current metatable. |
Return Value
Returns table — the same table you passed in. This is useful for chaining.
Basic Example
local fallback = {
__index = function(self, key)
return "default:" .. key
end
}
local t = {}
setmetatable(t, fallback)
print(t.name) --> default:name
print(t.any_key) --> default:any_key
Since setmetatable returns the table, you can do the setup in a single expression:
local t = setmetatable({}, {
__index = function(self, key) return "default:" .. key end
})
Removing a Metatable
Pass nil to strip the metatable:
local meta = {}
local t = {}
setmetatable(t, meta)
print(getmetatable(t) == meta) --> true
setmetatable(t, nil)
print(getmetatable(t) == nil) --> true
This fails silently if the metatable has a __metatable lock (see below).
Protected Metatables
If a metatable has a __metatable field, setmetatable cannot replace it. The call does nothing — it returns the table but the old metatable stays:
local protected = {
__metatable = "locked",
__index = function(self, k) return k end
}
local t = {}
setmetatable(t, protected)
setmetatable(t, {}) -- no effect
print(getmetatable(t) == protected) --> true
The __metatable value can be any Lua value. Use getmetatable to check before you try to change a metatable.
Real-World Example: Vector Type
Here’s how you might build a vector class with metatable behavior:
local function newVector(x, y)
return setmetatable({
x = x,
y = y
}, {
__add = function(a, b)
return newVector(a.x + b.x, a.y + b.y)
end,
__tostring = function(self)
return "(" .. self.x .. ", " .. self.y .. ")"
end,
__index = {
magnitude = function(self)
return math.sqrt(self.x ^ 2 + self.y ^ 2)
end
}
})
end
local v = newVector(3, 4)
print(v:magnitude()) --> 5.0
print(v + newVector(1, 1)) --> (4, 5)
Common Metamethods
These are the metamethods developers use most often:
| Metamethod | When it fires | Typical use |
|---|---|---|
__index | t[key] on a missing key | Default values, inheritance |
__newindex | t[key] = value on a missing key | Controlled writes, read-only tables |
__add | + operator | Vector addition, combining game objects |
__call | t() | Making objects callable |
__tostring | print(t) / tostring(t) | Human-readable debug output |
See Also
- /guides/lua-metatables/ — full guide to metatables and metamethods
- /tutorials/operator-overloading/ — using metamethods for operator overloading