I'm having trouble understanding why there is a difference in behavior of the __index
metamethod between these to examples:
A = { __index = A }
function A:speak()
print("I'm an A")
end
An_A = setmetatable({},A)
An_A:speak()
Will raise the following error: lua: l.lua:8: attempt to call method 'speak' (a nil value)
Whilst
B = { __index = function(t,key) return B[key] end }
function B:speak()
print("I'm an B")
end
An_B = setmetatable({},B)
An_B:speak()
Will perform as expected, outputting I'm an B
.
In trying to understand why this was the case I read this section of PiL. It states that:
The use of the __index metamethod for inheritance is so common that Lua provides a shortcut. Despite the name, the __index metamethod does not need to be a function: It can be a table, instead. When it is a function, Lua calls it with the table and the absent key as its arguments. When it is a table, Lua redoes the access in that table.
My understanding of this is that in the snippet involving 'A', __index = A
cause the access to be done in the table A
(as per the boldened segmenet of the above quote). If this is the case I don't understand why the function associated with the key "speak"
isn't found. In an attempt to try fix this, I decided to implement the function approach in the B
snippet, which returns the value associated with key
in B
, and it worked. Surely __index = A
and (adapted from B
) __index = function(t,key) return A[key] end
have the same effect.
Any clarification would be greatly appreciated.
What's happening in your first example is that A.__index == nil
. When you created 'A' on your first line here:
A = { __index = A }
The right-hand side of the the assignment 'A' evaluates to nil
since it doesn't exist yet at this point. As a result, later on when you set the metatable here:
An_A = setmetatable({},A)
it really ends up doing something akin to this:
An_A = setmetatable({}, {__index = nil} )
To get it to work the way you want, you have to make sure __index
isn't nil
. For example, assign it after table construction:
A = {}
A.__index = A
function A:speak()
print("I'm an A")
end
An_A = setmetatable({},A)
An_A:speak() --> outputs I'm an A
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With