CODE:
------------snip-----------
import std.stdio;
struct S {
int[] data;
int opCmp(const S s) const {
return (data < s.data) ? -1 : (data == s.data) ? 0 : 1;
}
}
void main() {
auto s = S([1,2,3]);
auto t = S([1,2,3]);
writeln(s==t);
writeln(typeid(s).compare(&s, &t)); // prints 16
}
------------snip-----------
Here, we defined opCmp to compare the array wrapped in S, and == correctly calls the custom opCmp to return true.
However, typeid(S) fails to call the custom opCmp; it appears to fall back to the default implementation of opCmp, which does a bitwise compare of S. This is a bug, because if the signature of opCmp is changed to:
int opCmp(ref const S s) const { ... }
then typeid(S) correctly calls the custom opCmp instead.
However, requiring ref in the argument is unnecessarily restrictive. If == works correctly without requiring a ref const argument, then why should typeid(S).compare require a ref const argument?
This bug is blocking issue #8435 and issue #10118.
Comment #1 by hsteoh — 2013-07-07T21:31:24Z
Furthermore, if opCmp is a template function, it is never picked up in the typeinfo. This makes it impossible to make typeinfo.compare behave correctly when you need to overload opCmp on templated argument types, because an IFTI bug makes it impossible to define both a template and non-template opCmp simultaneously.
Why the big deal with typeinfo.compare? If == works, isn't that good enough? It's not good enough because the AA implementation uses typeinfo.compare for key comparisons. Thus you have the situation where two AA keys compare equal on ==, and toHash is correctly defined so that the keys have equal hash values, but aa[key] does not work because typeinfo.compare uses the wrong key comparison function. This is one of the underlying issues in issue #8435 and issue #10567.
Comment #2 by hsteoh — 2013-07-07T21:34:09Z
Gah, I meant issue #10118.
Comment #3 by hsteoh — 2013-07-08T08:33:16Z
Temporary workaround: define int opCmp(ref const T t) const *before* any of the other opCmp overloads, and have it redirect to one of them.
Hi Kenji,
It seems that the latest pull has fixed this bug. Is there anything else that must be fixed? (You mentioned that this was only a "partial" fix?)
Comment #10 by k.hara.pg — 2013-08-05T02:54:04Z
(In reply to comment #9)
> Hi Kenji,
>
> It seems that the latest pull has fixed this bug. Is there anything else that
> must be fixed? (You mentioned that this was only a "partial" fix?)
The remain issue is that does not detect alias this opCmp correctly.
struct X
{
int opCmp(X) { return 0; }
}
struct S
{
int val;
X x;
alias x this;
}
void main()
{
S s1 = S(1);
S s2 = S(2);
assert(!(s1 < s2) && !(s1 > s2)); // OK
assert(s1.opCmp(s2) == 0); // OK
assert(typeid(S).compare(&s1, &s2) == 0); // doesn't work
}
Comment #11 by robert.schadek — 2024-12-13T18:08:54Z