🎓 A1Learner
🔍
0 of 52 lessons completed

Lua Metatable Chains

A metatable chain passes a missing key through more than one fallback table. Each fallback can pass the key on to the next fallback.

A missing key travels two fallbacks

A child table holds nothing. Its parent supplies one value, and a grandparent table supplies another.

local grandparent = {b = 2}
local parent = {a = 1}
local child = {}
setmetatable(parent, {__index = grandparent})
setmetatable(child, {__index = parent})
print(child.a, child.b)

Rawget skips the fallback

An item holds nothing, and its fallback holds a color. A direct read gives nil, while a normal read gives the color.

local defaults = {color = "red"}
local item = {}
setmetatable(item, {__index = defaults})
print(item.color, rawget(item, "color"))

Rawset skips the write intercept

A write intercept would send a new score to a store table. A direct write stores the score in the table itself instead.

local store = {}
local t = {}
setmetatable(t, {__newindex = function(t, k, v)
  store[k] = v
end})
rawset(t, "score", 9)
print(t.score, store.score)

Example

local defaults = {lang = "en", theme = "light"}
local u = {}
setmetatable(u, {__index = defaults})
print(u.lang)
rawset(u, "lang", "fr")
print(u.lang)
print(defaults.lang)

Key points

  • Chain: a series of fallback tables checked in order for a missing key.
  • First fallback: the __index field of the first table points to the next table in the chain.
  • Second fallback: that next table can have its own __index field pointing further along.
  • Rawget: rawget reads a table directly and skips every fallback in the chain.
  • Rawset: rawset writes a table directly and skips every write intercept in the chain.

In this example, a user table starts empty and reads its language from a defaults table. A direct write then stores a new language in the user table itself. The defaults table still holds the old language.

Note

a chain that points back to itself would loop, so chains in this lesson always move forward.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does a direct read give for a key that exists only in a fallback table?