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.