Bug 17206 – [Tracking] Check that opEquals and toHash are both defined or neither are defined

Status
NEW
Severity
normal
Priority
P3
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2017-02-20T13:09:41Z
Last change time
2024-12-01T16:29:42Z
Assigned to
No Owner
Creator
Seb
Depends on
18673, 18674, 18684, 18685, 18686, 18742, 18675, 18676, 18677, 18678, 18679, 18680, 18681, 18682, 18683, 18687
Moved to GitHub: phobos#9710 →

Comments

Comment #0 by greeenify — 2017-02-20T13:09:41Z
There's a Dscanner check for this: std/range/package.d(5748:12)[warn]: 'Cyclic' has method 'opEquals', but not 'toHash'. std/internal/test/dummyrange.d(363:8)[warn]: 'TestFoo' has method 'opEquals', but not 'toHash'. std/random.d(251:8)[warn]: 'LinearCongruentialEngine' has method 'opEquals', but not 'toHash'. std/random.d(995:8)[warn]: 'XorshiftEngine' has method 'opEquals', but not 'toHash'. std/datetime.d(9240:8)[warn]: 'Date' has method 'opCmp', but not 'opEquals'. std/datetime.d(13548:8)[warn]: 'TimeOfDay' has method 'opCmp', but not 'opEquals'. std/datetime.d(14822:8)[warn]: 'DateTime' has method 'opCmp', but not 'opEquals'. std/datetime.d(31723:14)[warn]: 'StopWatch' has method 'opEquals', but not 'toHash'. std/complex.d(99:8)[warn]: 'Complex' has method 'opEquals', but not 'toHash'. std/array.d(162:12)[warn]: 'Foo' has method 'opEquals', but not 'toHash'. std/functional.d(466:12)[warn]: 'Foo' has method 'opEquals', but not 'toHash'. std/container/rbtree.d(738:13)[warn]: 'RedBlackTree' has method 'opEquals', but not 'toHash'. std/container/array.d(249:8)[warn]: 'Array' has method 'opEquals', but not 'toHash'. std/container/dlist.d(170:8)[warn]: 'DList' has method 'opEquals', but not 'toHash'. std/container/slist.d(54:8)[warn]: 'SList' has method 'opEquals', but not 'toHash'. std/numeric.d(149:8)[warn]: 'CustomFloat' has method 'opCmp', but not 'opEquals'. std/json.d(101:8)[warn]: 'JSONValue' has method 'opEquals', but not 'toHash'. std/socket.d(1486:7)[warn]: 'InternetAddress' has method 'opEquals', but not 'toHash'. std/algorithm/searching.d(3235:19)[warn]: 'S2' has method 'opEquals', but not 'toHash'. std/uni.d(1205:8)[warn]: 'PackedArrayViewImpl' has method 'opEquals', but not 'toHash'. std/uni.d(1361:16)[warn]: 'SliceOverIndexed' has method 'opEquals', but not 'toHash'. std/uni.d(1899:15)[warn]: 'CodepointInterval' has method 'opEquals', but not 'toHash'. std/uni.d(3095:8)[warn]: 'CowArray' has method 'opEquals', but not 'toHash'.
Comment #1 by jack — 2018-03-28T13:08:50Z
I'm turning this into a tracking issue.
Comment #2 by n8sh.secondary — 2018-07-02T19:11:17Z
Half of this is wrong. For a type to be usable as a key in an associative array it must be true that "a == b" implies "a.toHash() == b.toHash()", so when there is a non-default `==` there should also be a custom `toHash` to maintain this property. But the reverse is not true: defining a non-default `toHash` does not require a custom `opEquals`, because the default `==` is already the strictest possible condition that satisfies "a == a" (since structs can be relocated).
Comment #3 by schveiguy — 2018-07-03T11:46:01Z
No, toHash doesn't necessarily have to follow the semantics of default opEquals. Example: struct S1(bool customTohash) { string s; static if(customTohash) { size_t toHash() const { return cast(size_t)s.ptr + s.length; // use string identity } /+ really should define this bool opEquals(const(S1) other) const { return other.s is s; } +/ } } void main() { bool[S1!false] aa1; aa1[S1!false("hello".idup)] = true; aa1[S1!false("hello".idup)] = true; assert(aa1.length == 1); bool[S1!true] aa2; aa2[S1!true("hello".idup)] = true; aa2[S1!true("hello".idup)] = true; assert(aa2.length == 1); // fails }
Comment #4 by schveiguy — 2018-07-03T11:49:46Z
(In reply to Steven Schveighoffer from comment #3) > bool[S1!true] aa2; > aa2[S1!true("hello".idup)] = true; > aa2[S1!true("hello".idup)] = true; > assert(aa2.length == 1); // fails > } The assert isn't telling the right story, really it should be that none of the keys are equal to each other. This is a better example: auto s1 = S1!true("hello".idup); auto s2 = S1!true("hello".idup); assert(s1 == s2) aa2[s1] = true; aa2[s2] = true; assert(aa2.length == 1);
Comment #5 by robert.schadek — 2024-12-01T16:29:42Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/phobos/issues/9710 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB