The answer, as is usual for extra-interesting code in Lua, is more metatables.
When your __index
metamethod is actually a table, Lua simply does a standard table access on the given table. This means you can set a metatable on your metatable. Then you can set an __index metamethod on this "meta-metatable".
foo = function()
print("foo")
end
bar = function(_, key)
return function()
print(string.format("bar: %s", key))
end
end
mmt = { __index = bar }
mti = { foo = foo }
mt = { __index = mti }
t = {}
setmetatable(mti, mmt)
setmetatable(t, mt)
t.foo() -- prints: "foo"
t.bar() -- prints: "bar: bar"
t.baz() -- prints: "bar: baz"
With this, when you try to access a field which is absent in both tables, lua will first try to access the top-level table which will access the first metatable which will then call your metamethod in the second metatable.
There is also another, possibly more straight forward, answer: Use your __index
metamethod to check another table for named fields:
foo = function()
print("foo")
end
f = { foo = foo }
bar = function(_, key)
if f[key] then return f[key] end
return function()
print(string.format("bar: %s", key))
end
end
mt = { __index = bar }
t = {}
setmetatable(t, mt)
t.foo() -- prints: "foo"
t.bar() -- prints: "bar: bar"
t.baz() -- prints: "bar: baz"
Tested on Lua 5.3.