luaequalitymeta-method

Lua __eq on tables with different metatables


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.


Solution

  • 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.