Search metamethod via __index?

I implemented my own class system and am having problems with __tostring ; I suspect that a similar problem may occur with other meta tags, but I have not tried.

(Short description: each class has an __classDict attribute containing all the methods. It is used as instances of the __index class. At the same time, __classDict __index is a superclass of __classDict so methods in superclasses are automatically scanned.)

I wanted to have default behavior in all instances. But this did not work: the behavior of "tostring" does not "propagate" through subclasses correctly.

I did this test illustrating my problem:

 mt1 = {__tostring=function(x) return x.name or "no name" end } mt2 = {} setmetatable(mt2, {__index=mt1}) x = {name='x'} y = {name='y'} setmetatable(x, mt1) setmetatable(y, mt2) print(x) -- prints "x" print(mt2.__tostring(y)) -- prints "y" print(y) -- prints "table: 0x9e84c18" !! 

I would prefer the last line to print "y".

Lua "to_String" behavior should use equivalent

 rawget(instance.class.__classDict, '__tostring') 

instead of doing the equivalent

 instance.class.__classDict.__tostring 

I suspect this is happening with all metamethods; rawget operations.

I think that one thing I could do is copy all metamethods when I do subclasses (the equivalent in the above example would be mt2.__tostring = mt1.__tostring ), but it's kind of inelegant.

Has anyone fought such a problem? What, where are your decisions?

+4
source share
4 answers

Thanks to the comments of the daniator, I think I found a way to make the "follow" __index as I want. It has condensed by this function:

 local metamethods = { '__add', '__sub', '__mul', '__div', '__mod', '__pow', '__unm', '__concat', '__len', '__eq', '__lt', '__le', '__call', '__gc', '__tostring', '__newindex' } function setindirectmetatable(t, mt) for _,m in ipairs(metamethods) do rawset(mt, m, rawget(mt,m) or function(...) local supermt = getmetatable(mt) or {} local index = supermt.__index if(type(index)=='function') then return index(t,m)(...) end if(type(index)=='table') then return index[m](...) end return nil end) end return setmetatable(t, mt) end 

Hope it's easy enough. When a new metatet is installed, it initializes it with all metamethods (without replacing the existing ones). These metamethods are ready to "pass" requests to the "parent meta tags."

This is the easiest solution I could find. Well, I actually found a solution that used fewer characters and was a bit faster, but it was about black magic (it involved metatable functions, de-references to itself), and it was much less readable than this.

If someone finds a shorter, simpler function that does the same, I will gladly give him the answer.

The usage is simple: replace setmetatable with setindirectmetatable if you want it to "go up":

 mt1 = {__tostring=function(x) return x.name or "no name" end } mt2 = {} setmetatable(mt2, {__index=mt1}) x = {name='x'} y = {name='y'} setmetatable(x, mt1) setindirectmetatable(y, mt2) -- only change in code print(x) -- prints "x" print(mt2.__tostring(y)) -- prints "y" print(y) -- prints "y" 

A small warning word: setindirectmetatable creates meta tags on mt2. Changing this behavior to make a copy while mt2 remains unchanged should be trivial. But letting them configure the default is actually better for my purposes.

+1
source

I suspect this is happening with all metamethods; operations with the equivalent of rawget are used.

It is right. from the lua manual:

... should be read as rawget(getmetatable(obj) or {}, event) . That is, access to the metamethod does not call other metamethods, and access to objects without metadata is not interrupted (this simply leads to zero).

As a rule, each class has its own meta-furniture, and you copy all the references to functions into it. That is, do mt2.__tostring = mt1.__tosting

+3
source

From my experience with Lua 5.1, meta tags are looked up in metatables using rawget (), and so you must copy the function reference into every class table that you create.

0
source

See the Wiki Inheritance Tutorial for Lua Users.

-1
source

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


All Articles