luaguides

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

ParameterTypeDescription
tabletableThe 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.
metatabletable or nilThe 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:

MetamethodWhen it firesTypical use
__indext[key] on a missing keyDefault values, inheritance
__newindext[key] = value on a missing keyControlled writes, read-only tables
__add+ operatorVector addition, combining game objects
__callt()Making objects callable
__tostringprint(t) / tostring(t)Human-readable debug output

See Also