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!