July 21, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 --- Comment #1 from Jacob Carlborg <doob@me.com> --- Reduced test case: struct TagIndex { uint tag, index; const int opCmp(ref const TagIndex o) { if (tag == o.tag && index == o.index) return 0; if (tag > o.tag) return 1; if (tag < o.tag) return -1; if (index > o.index) return 1; if (index < o.index) return -1; assert(0); } } int[TagIndex] a; -- |
July 21, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 hsteoh@quickfur.ath.cx changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |hsteoh@quickfur.ath.cx -- |
July 21, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 --- Comment #2 from Kenji Hara <k.hara.pg@gmail.com> --- (In reply to Jacob Carlborg from comment #0) > Building Tango with 2.066.0-b5 results in the following error: > > tango/text/Regex.d(2532): Error: AA key type TagIndex now requires equality > rather than comparison > tango/text/Regex.d(2532): Please define opEquals, or remove opCmp to > also rely on default memberwise comparison. > > I can see that opEquals should be used and not opCmp for AA keys, but if opCmp is defined, why doesn't the compiler automatically generate opEquals that calls opCmp? It's intended behavior, because compiler cannot know whether the generated opEquals is what programmer is expecting. (In reply to Jacob Carlborg from comment #1) > Reduced test case: > > struct TagIndex > { > uint tag, index; > > const int opCmp(ref const TagIndex o) > { [snip] > } > } > > int[TagIndex] a; In D, all struct define default member-wise equality for == operator. TagIndex t1, t2; // t1 == t2 will be rewritten as: // t1.tupleof == t2.tupleof // and then it will mean: // t1.tag == t2.tag && t1.index == t2.index If TagIndex is used for AA keys, compiler cannot determine which is the intended 'equality', t1 == t2 or t1.opCmp(t2) == 0. So compiler requests you to resolve the ambiguity by defining opEquals or removing opCmp. -- |
July 21, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 bearophile_hugs@eml.cc changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |bearophile_hugs@eml.cc --- Comment #3 from bearophile_hugs@eml.cc --- (In reply to Kenji Hara from comment #2) > If TagIndex is used for AA keys, compiler cannot determine which is the intended 'equality', t1 == t2 or t1.opCmp(t2) == 0. opCmp includes an equality, this means the programmer has defined an equality too. So can't we assume that the equality is "t1.opCmp(t2) == 0" when the user defines just opCmp? -- |
July 21, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 --- Comment #4 from hsteoh@quickfur.ath.cx --- (In reply to Kenji Hara from comment #2) [...] > It's intended behavior, because compiler cannot know whether the generated opEquals is what programmer is expecting. [...] That doesn't make sense. The programmer has already defined opCmp, which means "a == b" is already compiled to be "a.opCmp(b)==0". Therefore, if the programmer didn't define opEquals, it should simply default to: ---- bool opEquals(T b) { return a.opCmp(b)==0; } ---- By your logic, the compiler should reject "a == b" when the programmer hasn't defined opEquals, because the compiler cannot know whether a.opCmp(b)==0 is what the programmer is expecting. I don't understand how this could make any sense. -- |
July 22, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 --- Comment #5 from Jacob Carlborg <doob@me.com> --- (In reply to Kenji Hara from comment #2) > It's intended behavior, because compiler cannot know whether the generated opEquals is what programmer is expecting. As others have already said, if opCmp is defined then the compiler can generate opEquals that calls opCmp. > In D, all struct define default member-wise equality for == operator. > > TagIndex t1, t2; > // t1 == t2 will be rewritten as: > // t1.tupleof == t2.tupleof > // and then it will mean: > // t1.tag == t2.tag && t1.index == t2.index > > If TagIndex is used for AA keys, compiler cannot determine which is the intended 'equality', t1 == t2 or t1.opCmp(t2) == 0. > > So compiler requests you to resolve the ambiguity by defining opEquals or removing opCmp. opCmp was added because of a regression in 2.065.0 and now it's changed again. -- |
July 23, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 --- Comment #6 from Kenji Hara <k.hara.pg@gmail.com> --- (In reply to Jacob Carlborg from comment #5) > opCmp was added because of a regression in 2.065.0 and now it's changed again. So you can just remove opCmp completely. For the struct struct TagIndex { uint tag, index; } In 2.066 AA will use default member-wise equality and hasing. -- |
July 23, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 Kenji Hara <k.hara.pg@gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |RESOLVED Resolution|--- |INVALID --- Comment #7 from Kenji Hara <k.hara.pg@gmail.com> --- (In reply to bearophile_hugs from comment #3) > opCmp includes an equality, this means the programmer has defined an equality too. So can't we assume that the equality is "t1.opCmp(t2) == 0" when the user defines just opCmp? But currently `a == b` is never rewritten to `a.opCmp(b) == 0`. It's in a domain of enhancement request that requires more discussion. (In reply to hsteoh from comment #4) > By your logic, the compiler should reject "a == b" when the programmer hasn't defined opEquals, because the compiler cannot know whether a.opCmp(b)==0 is what the programmer is expecting. I don't understand how this could make any sense. It's not a logic issue. If opCmp is defined and `a == b` will be automatically rewritten to `a.opCmp(b) == 0`, the code behavior will be _silently_ changed. So compiler reports a diagnostic error. It's far better than silent changing. -- |
July 23, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 hsteoh@quickfur.ath.cx changed: What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |REOPENED Resolution|INVALID |--- --- Comment #8 from hsteoh@quickfur.ath.cx --- (In reply to Kenji Hara from comment #7) [...] > But currently `a == b` is never rewritten to `a.opCmp(b) == 0`. It's in a domain of enhancement request that requires more discussion. Wait, wat?? That's ridiculous... I think this is a bug. If I define opCmp, then a==b should work even if I don't define opEquals. Otherwise this leads to the current ridiculous situation: ------ struct S { int x; int y; int opCmp(S s) { return x - s.x; } } void main() { auto s1 = S(1,2); auto s2 = S(1,3); auto s3 = S(2,1); assert(s1 < s3); // OK assert(s2 < s3); // OK assert(s3 > s1); // OK assert(s3 > s2); // OK assert(s1 <= s2 && s2 >= s1); // OK assert(s1 == s2); // FAIL } ------ The last two lines show that s1<=s2 && s1>=s2 does not imply s1==s2. I find that difficult to accept. I think this needs to be fixed. > (In reply to hsteoh from comment #4) > > By your logic, the compiler should reject "a == b" when the programmer hasn't defined opEquals, because the compiler cannot know whether a.opCmp(b)==0 is what the programmer is expecting. I don't understand how this could make any sense. > > It's not a logic issue. If opCmp is defined and `a == b` will be automatically rewritten to `a.opCmp(b) == 0`, the code behavior will be _silently_ changed. > > So compiler reports a diagnostic error. It's far better than silent changing. I think that any code depends on the fact that s1<=s2 && s1>=s2 doesn't imply s1==s2, is already horribly broken. -- |
July 23, 2014 [Issue 13179] AA key type TagIndex now requires equality rather than comparison | ||||
---|---|---|---|---|
| ||||
https://issues.dlang.org/show_bug.cgi?id=13179 Jonathan M Davis <jmdavisProg@gmx.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jmdavisProg@gmx.com --- Comment #9 from Jonathan M Davis <jmdavisProg@gmx.com> --- I would not expect `a == b` to _ever_ be converted to `a.opCmp(b) == 0`. That's what opEquals is for. However, I also wouldn't expect declaring opCmp to make it so that the compiler no longer generates an opEquals for the struct. The compiler should either continue to declare the opEquals or make it an error if you define opCmp but not opEquals. It makes no sense whatsoever to have a type which is comparable with <, <=, >=, and > but not ==. And it should _always_ be considered a bug if `a.opCmp(b) == 0` is not equivalent to `a == b` or if `a <= b && a >= b` is not equivalent to `a == b`. -- |
Copyright © 1999-2021 by the D Language Foundation