Lua Metatable Mismatch

I am having trouble understanding why there is a difference in the behavior of the __index __index between these 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)

While

 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 be executed as expected, outputting I'm an B


In an attempt to understand why this was so, I read this section of PiL. It states that:

Using __index metadata for inheritance is so common that Lua provides a shortcut. Despite the name, the __index metadata does not need to be a function: instead, it can be a table. When these are functions, Lua calls it a table and a missing key as arguments. When it is a table, Lua redefines access in this table.

My understanding of this is that in the fragment including "A", __index = A , you should make access in table A (according to the offset segment of the above quote). If so, I don’t understand why the function associated with the "speak" key was not found. To try to fix this, I decided to implement a functional approach in fragment B , which returns the value associated with key in B , and it worked. Of course, __index = A and (adapted from B ) __index = function(t,key) return A[key] end have the same effect.

Any clarification would be greatly appreciated.

+6
source share
1 answer

What happens in the first example is A.__index == nil . When you created "A" on your first line here:

 A = { __index = A } 

The right-hand side of the assignment 'A' evaluates to nil , since it does not yet exist at this point. As a result, later when you set the meta here:

 An_A = setmetatable({},A) 

he really ends up doing something similar to this:

 An_A = setmetatable({}, {__index = nil} ) 

To make it work the way you want, you need to make sure that __index not nil . For example, assign it after building the table:

 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 
+9
source

Source: https://habr.com/ru/post/944750/


All Articles