1

I have Lua objects which share a metatable which has a __eq metamethod. Inside this meta method, I want to check if the two objects are the same object before even comparing them. Similar to how in java you would do a == b || a.compareTo(b). The issue though is by doing == inside of __eq, it calls __eq and thus Stack Overflow. How can I achieve this?

local t1 = { x = 3 }
local t2 = { x = 3 }
local t3 = t1
print(t1 == t3) -- true, they pointer to same memory
local mt = {
    __eq = function(lhs, rhs)
        if lhs == rhs then return true end -- causes stack overflow
        return lhs.x == rhs.x
    end
}
setmetatable(t1, mt)
setmetatable(t2, mt)

-- stack overflow below
print(t1 == t2) -- this should compare 'x' variables
print(t1 == t3) -- this shouldn't need to do so, same memory location
Hatefiend
  • 3,416
  • 6
  • 33
  • 74

2 Answers2

2

Check rawequal() function. It will compare instances without calling metamethods.

Vlad
  • 5,450
  • 1
  • 12
  • 19
2

There is no need to test for equality inside the __eq metamethod because Lua only calls the __eq metamethod if the userdata pointers are different.

Add print(t1 == t3) right after setting the metatables to confirm this.

The manual says (emphasis added):

__eq: 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.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • Ah wow I should have given metamethods more credit to be smart enough to do that. Putting a print inside the `__eq` proves this to be true. Thanks for the help. – Hatefiend Feb 03 '18 at 11:16