Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua/Luajit: Indexing and named method at the same time?

Tags:

lua

ffi

luajit

The Lua PIL and Luajit FFI tutorial gave two usages of __index in the metatable.

One is for indexing like obj[123], e.g.,

__index = function (self, k) return self._data+(k-self._lower)

The other usage is to define named methods, as given in the tutorial,

__index = { area = function(a) return a.x*a.x + a.y*a.y end, },

We can then make function call like obj:area().

Can I do both at the same time, e.g., direct indexing and named methods?

like image 876
Liang Avatar asked Oct 29 '18 17:10

Liang


1 Answers

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.

like image 132
azdle Avatar answered Oct 21 '22 05:10

azdle