Try giving the official source a read, specifically §2.4 – Metatables and Metamethods
, and the description of the __index
methamethod, which reads:
__index: The indexing access table[key]
. This event happens when table is not a table or when key is not present in table. The metamethod is looked up in table.
Despite the name, the metamethod for this event can be either a function or a table. If it is a function, it is called with table and key as arguments, and the result of the call (adjusted to one value) is the result of the operation. If it is a table, the final result is the result of indexing this table with key. (This indexing is regular, not raw, and therefore can trigger another metamethod.)
We can see that your thinking is backwards. Properties on a table referenced by the __index
metamethod are only looked up if the original table does not contain the key.
If you want to 'hook' a function you'll need to overwrite it, possibly saving the original to restore it later. If you want to tack functionally on to an existing function, you can write a neat little hooking function, which simply creates a closure around the functions, calling them in turn.
local function hook (original_fn, new_fn)
return function (...)
original_fn(...)
new_fn(...)
end
end
local test = {}
test.foo = function () print('hello') end
test.foo = hook(test.foo, function () print('world!') end)
test.foo() --> prints 'hello' then 'world!'
Alternatively, you can switch between metatables, assuming the original table never overrides the keys of interest, to get different results:
local my_table, default, extra = {}, {}, {}
function default.foo () print('hello') end
function extra.foo() print('world!') end
local function set_mt (t, mt)
mt.__index = mt
return setmetatable(t, mt)
end
set_mt(my_table, default)
my_table.foo() --> prints 'hello'
set_mt(my_table, extra)
my_table.foo() --> prints 'world!'