lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2015-12-31 14:14 GMT+02:00 Philipp Janda <siffiejoe@gmx.net>:
> Am 31.12.2015 um 12:41 schröbte Dirk Laurie:
>>
>> 2015-12-31 10:34 GMT+02:00 Marc Balmer <marc@msys.ch>:
>>
>>> When a nested __index metamethod is being called, does
>>> it still get the original table as the first argument, or the table
>>> that caused this __index metamethod to be called (i.e. the
>>> previously indexed table)?
>
>
> It's a dozen lines of Lua code to figure this out, and it would have
> prevented a lot of confusion:
>
>     local mt = {
>       __index = setmetatable( {}, {
>         __index = function( o, k )
>           print( o, k )
>         end
>       } )
>     }
>     local t = setmetatable( {}, mt )
>
>     print( "t", t )
>     print( "mt.__index", mt.__index )
>     local dummy = t.x
>
> Typical output:
>
>     t   table: 0x1d16060
>     mt.__index  table: 0x1d16530
>     table: 0x1d16530    x
>
>>
>> It's a tail call. I.e. all that happens is that exactly the same
>> stack is presented to the new function. Since the original
>> table was the first argument, it still is.
>>
>
> If I understand the question correctly, this is wrong. See above.

What I understand by nesting metatables is that each time
__index is another table, and in that case my answer is right:
The method eventually called receives the table itself.

local method1 = function(object)
   print("Method1 of "..object.name.." has been called")
end

local method2 = function(object)
   print("Method2 of "..object.name.." has been called")
end

local method3 = function(object)
   print("Method3 of "..object.name.." has been called")
end

local table1 = {name="foo", m1 = method1}
local table2 = {name="bar", m2 = method2}
local table3 = {name="zyx", m3 = method3}

setmetatable(table1, {__index = f1})
setmetatable(table2, {__index = f2})

table1:m3() --> Method3 of foo has been called

Having reread Marc's post, I agree that your example is what
he means, though. His agenda seems to be something like:

1. If table1[k] exists, return it.
2. Else if table2[k] exists, return it.
3. Else if table3[k] exists, return it.
....
n+1. Otherwise return fct(table1,k).

The way to achieve that is to put the function first.

setmetatable(table1, {__index = function(tbl,k)
   return table2[k] or fct(table1,k)
   end})

All the other tables can be accessed via nested __index
tables for table2.

How to understand why table1 does not propagate to the function?
Let me dissect your example.

local mt1 = {}
local mt2 = {}
local index1 = {}
local t = {}

setmetatable( t, mt1 )
setmetatable( index1, mt2)
mt1.__index = index1

function mt2:__index(k)
  print(self,k)
end

print( "t", t )
print( "index1", index1 )
local dummy = t.x

>From this it is clear that "self" is the table of which mt2
is the metatable, i.e. index1.