Incorrect Meta-Methods Behaviour

What do I want to achieve? To report an engine bug or a mistake in documentation, but I don’t have permission to do so. :sweat_smile:

What is the issue? The meta-methods __lt and __le don’t fire in the way stated here:

The documentation says that __lt will fire when < and >= is used, and that >= will cause the return to be inversed. The same applies for __le but with <= and > instead. However, it turns out that < and > fire __lt; <= and >= fire __le.

What solutions have you tried so far? I can’t really make a solution myself, other than work around the odd behaviour.

Here’s some code so you can replicate the issue yourself:

local metaTbl = {
	__lt = function(tbl, value)
		print("__lt")
	end,
	
	__le = function(tbl, value)
		print("__le")
	end
}

local tbl1 = setmetatable({"1"}, metaTbl)
local tbl2 = setmetatable({"2"}, metaTbl)

local test1 = tbl1 > tbl2 -- prints __lt
local test2 = tbl1 < tbl2 -- prints __lt

local test3 = tbl1 >= tbl2 -- prints __le
local test4 = tbl1 <= tbl2 -- prints __le

I’m not sure whether this behaviour is intended and the documentation is wrong, or visa versa, but there’s clearly a discrepancy.

1 Like

Hi @shadowflame63! I didn’t believe it until I tried it myself. You’re absolutely right that there appears to be a discrepancy. I did some testing myself and found the behavior to still achieve the correct results, however not in the manner as stated in the documentation. Here’s an example of how I found it to work:

local dogMeta = {
	__lt = function(lhs, rhs)
		print("Evaluating __lt:", lhs.Name, "<", rhs.Name)
		return lhs.Age < rhs.Age
	end,
	
	__le = function(lhs, rhs)
		print("Evaluating __le:", lhs.Name, "<=", rhs.Name)
		return lhs.Age <= rhs.Age
	end,
}

local Dog = {
	new = function(name, age)
		local newDog = {
			Name = name,
			Age = age
		}
		return setmetatable(newDog, dogMeta)
	end,
}

local dog1 = Dog.new("Bandit", 2)
local dog2 = Dog.new("Fido", 4)
local dog3 = Dog.new("Rockie", 2)

print(dog1 < dog2)  --Evaluating __lt: Bandit < Fido // true
print(dog1 <= dog2) --Evaluating __le: Bandit <= Fido // true
print(dog1 > dog2)  --Evaluating __lt: Fido < Bandit // false
print(dog1 >= dog2) --Evaluating __le: Fido <= Bandit // false

print(dog1 < dog3)  --Evaluating __lt: Bandit < Rockie // false
print(dog1 <= dog3) --Evaluating __le: Bandit <= Rockie // true
print(dog1 > dog3)  --Evaluating __lt: Rockie < Bandit // false
print(dog1 >= dog3) --Evaluating __le: Rockie <= Bandit // true

In this brief example I just implemented a simple Dog class where its metatable includes relational operators that compare the Age property of two Dog instances. For each comparison the correct result is achieved, but not by calling the opposite operator and negating, but instead by reversing the order of the operands (aka which Dogs are being compared). See print statements 3,4,7, and 8 for occurrences of operand flipping.

For a purely mathematical example, the documentation states that 1 > 2 should invoke the __le metamethod and compute not 1 <= 2, however it actually invokes the __lt metamethod and computes 2 < 1. Both approaches reach the same conclusion of false.

Although I’m not entirely sure, the documentation may be wrong because it was intended for use with an earlier version of Lua (and definitely not for Luau) and the change in method may have been due to some performance benefit from flipping the operands vs. computing the negation of the opposite operation. Additionally, this change may have been made due to the user-defined behavior of these, and all other metamethods; For some very specific use cases <, <=, >, >= (and other operators) might serve a different purpose than their mathematically symbol denotes… But that’s a story for a different time.

I don’t have permissions to post bug reports in the Developer Hub forum either, so in the meantime I hope this explanation helped clear up any confusion produced by the inaccurate documentation!

1 Like

I think you’re right with the flipping of the operands, so it must be the documentation that’s outdated.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.