Bug 669 – (a == b) misuses opCmp and opEquals

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D1 (retired)
Platform
x86
OS
Windows
Creation time
2006-12-09T11:33:00Z
Last change time
2014-02-15T13:19:43Z
Assigned to
bugzilla
Creator
burton-radons

Comments

Comment #0 by burton-radons — 2006-12-09T11:33:39Z
This code: class C { override int opEquals (Object other) { return 0; } override int opCmp (Object other) { return 0; } } void main () { auto a = new C, b = new C; assert (a != b); } Asserts, because (a == b) is apparently implemented as (a.opEquals (b) || !a.opCmp (b)) for classes. If this were the way it should work, then "float.nan == 0" would be true. It's the "!<>" operator that's defined with this behaviour.
Comment #1 by smjg — 2006-12-10T12:12:01Z
Under DMD 0.177, the code doesn't even compile: opCmpEquals_2.d(9): semicolon expected following auto declaration, not ',' opCmpEquals_2.d(9): found ',' instead of statement But having fixed this error, the bug doesn't show at all. Experimenting shows that: == and != use only opEquals <> and !<> use only opCmp which is how it should be. WFM?
Comment #2 by burton-radons — 2006-12-10T13:43:23Z
Grah I'm a stupid. Here's code which actually exhibits the problem: class C { override int opEquals (Object other) { printf ("opEquals\n"); return 0; } override int opCmp (Object other) { printf ("opCmp\n"); return 0; } } void main () { auto type = typeid (typeof (C)); void *data = new C; assert (type.equals (&data, &data) == 0); } The fault is TypeInfo_Class in internal.object. It's implemented like this: int equals(void *p1, void *p2) { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; return o1 == o2 || (o1 && o1.opCmp(o2) == 0); } When it should be implemented like this: int equals(void *p1, void *p2) { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; return o1 == o2; } This problem showed itself because I was comparing boxed objects, so I assume it's written the way it is now for associative arrays. If so then associative arrays should have their own slot in a TypeInfo for performing this (unorderedOrEqual), and std.boxer can have a pure form with the correct semantics for ==. Otherwise std.boxer's Box.opEqualsInternal can have a clause for objects.
Comment #3 by smjg — 2006-12-10T16:58:19Z
(In reply to comment #2) > When it should be implemented like this: > > int equals(void *p1, void *p2) > { > Object o1 = *cast(Object*)p1; > Object o2 = *cast(Object*)p2; > > return o1 == o2; > } I could've sworn this was fixed once! Moreover, that's still not quite right. It should be int equals(void *p1, void *p2) { if (p1 == null) return p2 == null; Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; return o1 == o2; } or some equivalent of this.
Comment #4 by bugzilla — 2006-12-27T02:02:31Z
Fixed DMD 0.178