Lua __eq on tables with different metatables

2.3k Views Asked by At

I have found the following quote on this site http://lua-users.org/wiki/MetamethodsTutorial:

__eq is called when the == operator is used on two tables, the reference equality check failed, and both tables have the same __eq metamethod (!).

Now I tested it with Lua 5.3.5 and this is not at all what I observed:

a = {}
b = {}
m = {}
m2 = {}
setmetatable(a, m)
setmetatable(b, m2)
m.__eq = function(p1, p2) print("why"); return true end
m2.__eq = function(p1, p2) print("why2"); return true end

This is the code I tested with.

> a == b
why
true
> b == a
why2
true

It looks like it does the same thing as with the comparison operators, where it just takes the left table and uses its metamethod.

Did this change in recent Lua versions or did I make an error with my test?

Thanks for your help.

1

There are 1 best solutions below

1
On BEST ANSWER

That changed in Lua 5.3. The readme says it introduced "more flexible rules for some metamethods". Compare the Lua 5.2 reference manual:

the == operation. The function getequalhandler defines how Lua chooses a metamethod for equality. A metamethod is selected only when both values being compared have the same type and the same metamethod for the selected operation, and the values are either tables or full userdata.

     function getequalhandler (op1, op2)
       if type(op1) ~= type(op2) or
          (type(op1) ~= "table" and type(op1) ~= "userdata") then
         return nil     -- different values
       end
       local mm1 = metatable(op1).__eq
       local mm2 = metatable(op2).__eq
       if mm1 == mm2 then return mm1 else return nil end
     end

The "eq" event is defined as follows:

     function eq_event (op1, op2)
       if op1 == op2 then   -- primitive equal?
         return true   -- values are equal
       end
       -- try metamethod
       local h = getequalhandler(op1, op2)
       if h then
         return not not h(op1, op2)
       else
         return false
       end
     end

Note that the result is always a boolean.

With the Lua 5.3 reference manual:

the equal (==) operation. Behavior similar to the addition operation, except that Lua will try a metamethod only when the values being compared are either both tables or both full userdata and they are not primitively equal. The result of the call is always converted to a boolean.