-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
An error in the logic of util.deepcompare? #125
Comments
As written in the source, I took the logic from Penlight. Comparison of tables with different metatables in Lua is complicated. For instance:
As you can see, when both members have an I think what Penlight is doing for deep comparison (only take the first parameter into account to check if a metatable should be used, i.e. "cast the second parameter to the type of the first one") is a good trade-off. |
@catwell I agree that comparison once metatables are involved gets very complicated. However, that last result really bothers me. That said, I'm not sure of the right alternative. Here's one thought. Change my last attempt above into this: local mt1 = getmetatable(t1)
local mt2 = getmetatable(t2)
if (mt1 and mt1.__eq) or (mt2 and mt2.__eq) then
return t1 == t2 and t2 == t1
end I'm aksing for my parallel method in tapered. At the moment, I'm trying something much more complicated than I like, but I'm trying to catch all possible cases. |
@telemachus Yes, that makes sense. It can be inefficient, but does it really matter in test helpers? |
@catwell To me that (tiny?) inefficiency is less important than a wrong result. But I can imagine cases where people would vote the other way. |
Inefficiency is not always that tiny. Think about what happens if you are comparing trees and |
Regarding the luassert code: the real bug IMO is that the code does not do what the comment says. If |
I agree with @catwell's last comment, |
@catwell @o-lim I think that there is an important difference here between Lua 5.3 and earlier versions. In Lua 5.2, a call to In Lua 5.3, a call to
So perhaps luassert is relying on |
Right. To be honest I had to check with an interpreter, and I had not realized this had changed in 5.3. I almost never overload operators in my own code. |
A reason given on the lua mailing list for not required equality of metatables is that it rules out (some kinds of) inheritance. I'm not sure how relevant that is to anyone's choices in this thread, but it makes sense to me as one concern that some people may have. Reference: http://listmaster.pepperfish.net/cgi-bin/mailman/private/lua-l-lists.lua.org/2015-July/049132.html |
In either case, I think be using |
I agree with you about the change you've proposed as a PR.
I had written a version of
On the lua mailing list, Roberto's attitude to my worries about noncommutative |
The current implementation of
util.deepcompare
has a result that is counter-intuitive (to me) in the following case:According to
util.deepcompare
,foo
andbar
are the same, but that seems wrong. (They don't both have the same metatable.bar
has no metatable at all.) The problem comes in the fourth line here inutil.deepcompare
:Because the two tables do not have equal metatables, they are not compared using
==
. Instead, they are handed off to the key, value checking further down. Since they both have the same single item—4—they appear the same by those sorts of checks.This may be a judgment call, but
util.deepcompare
seems to me to give the wrong result. If two tables are being compared, and one has a metatable and the other doesn't, then that very fact means they are not (at a deep level) the same. underscore and cwtest would consider foo and bar different because they handle the metatable branch the following way:Sorry for the novel, but I wanted to see if the result was expected by you before making a PR to change anything. Thanks.
Edit: After thinking this over, I now think it's even more complicated.
util.deepcompare
is wrong to considerfoo
andbar
the same table, but underscore and cwtest have a parallel problem. In their case, the problem is about order: what if the second (but not the first) table has a metatable with.__eq
? Their way of handling things won't detect this, and they will wrongly call two subtly different tables the same.So the full logic should be this:
/ping @catwell and @mirven
The text was updated successfully, but these errors were encountered: