What does it mean for opCmp and opEquals to be consistent?

Jonathan M Davis jmdavisProg at gmx.com
Thu Apr 3 03:15:06 PDT 2014


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


More information about the Digitalmars-d-learn mailing list