On Thursday, April 03, 2014 07:10:06 dnspies wrote: > To make a struct a valid key type, do I need to implement both > opCmp and opEquals or just one or the other? It says on the page > about associative arrays: "The implementation may use either > opEquals or opCmp or both." Does that mean it uses whichever one > is user-defined (or both if they're both user-defined)? Or does > it mean the user is responsible for defining both? > > Immediately after that it says: > "Care should be taken so that the results of > opEquals and opCmp are consistent with each other when the > struct/union objects are the same or not.", certainly this means > that if a.opEquals(b), then a.opCmp(b) should be 0, but does the > converse have to be true?
_Any_ type which overloads both opEquals and opCmp and does not make them match exactly is just plain broken. If a.opEquals(b) is true, then a.opCmp(b) must be 0. If a.opEquals(b) is false, then a.opCmp(b) must be non-zero. If a.opCmp(b) is 0, then a.opEquals(b) must be true. If a.opCmp(b) is non-zero, then a.opEquals(b) must be false. Think of how integers work with ==, <=, <, >, >=, and !=. If a user-defined type does not follow the same logic for how those operators are related (e.g. == implies that <= and >= are true and that <, >, and != are false), then it's broken and will likely fail to work properly with generic code. Don't get cute and try and make them mean something different than they mean with integers. In general, D's operator overloading was designed with the idea that you wouldn't try to overload the operators to mean anything different from what they mean with the built-in types, and you're just going to run into trouble if you try (unlike C++, which is far less restrictive about it and lets you do pretty much whatever you want with overloaded operators). There _are_ types where it makes sense to define opEquals but not opCmp, because they're comparable but not sortable. So, just because you define opEquals does not mean that you need to define opCmp. Also, if the default- generated opEquals does what you need, then you'd only need to define opCmp and not opEquals - but you'd still need to make it so that the opCmp implementation matched the default-generated opEquals, or you'd be in trouble. Now, as to AAs specifically, if you try and do struct S { int i; } void main() { int[S] aa; } you get an error message complaining about opCmp not being defined, so apparently the compiler expects the AA implementation to use opCmp (though I have no idea if it currently does), and you're going to need to define it. - Jonathan M Davis