[Issue 13179] AA key type TagIndex now requires equality rather than comparison

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Wed Jul 23 12:21:57 PDT 2014


https://issues.dlang.org/show_bug.cgi?id=13179

--- Comment #13 from Jonathan M Davis <jmdavisProg at gmx.com> ---
(In reply to hsteoh from comment #12)
> Nobody is talking about calling opCmp or opEquals directly here. The issue
> here is that == does not behave consistently with <, <=, >=, > when the user
> defines opCmp (but not opEquals). Either we should *reject* such code (i.e.,
> the user must always explicitly define opEquals if opCmp is defined), or we
> should do the Right Thing, that is, make opEquals the same as opCmp()==0.

I'd be in favor of either making it an error to define opCmp but not opEquals,
letting the programmer just screws themselves if they define opCmp so that it
doesn't match the compiler-generated opEquals, and they don't define opEquals
themselves (which would basically be the same as if they defined both but
didn't make them consistent).

The advantage of not requiring that opEquals be defined and still using the
default one is that you wouldn't have to define opEquals just because you
defined opCmp when the default opEquals did what you wanted (which it probably
does in the majority of cases).

The advantage of requiring opEquals is that it makes it clear that the
programmer needs to make sure that opCmp is consistent with opEquals, but it
doesn't necessarily make it less error-prone, because the programmer then needs
to define opEquals to be equivalent to a.opCmp(b) == 0, and they can screw that
up, so there's no guarantee that a.opCmp(b) == 0 is equivalent to opEquals,
even if it's supposed to be. And they're probably _more_ likely to define
opEquals incorrectly than the default one if what they want is what the default
one does (also, they'd generally lose out on whatever efficiency gains the
default one might have if they define it themselves).

Using a.opCmp(b) == 0 for opEquals if opEquals isn't defined would guarantee
correctness, but it would incur a performance hit, and I'm willing to bet that
a lot of folks would expect the normal, compiler-generated opEquals to still be
generated even when opCmp is declared (I certainly would have), so they
wouldn't realize that they were getting a performance hit. And those that
didn't think it through even that far wouldn't know about the performance hit
either.

And there's toHash to consider as well. It needs to be consistent with
opEquals, and it won't be if opEquals is defined by the user but not toHash -
making it so that toHash should probably be required by the AA to be explicitly
defined by the type if opEquals has been declared and so that if toHash is
declared, opEquals should be required. Regardless, there is no option in that
case to use another function to guarantee correctness (as you can do by using
opCmp for opEquals). So, we _still_ require correctness of the user. Also, if
the compiler-generate opEquals is used when opCmp is declared, then the
compiler-generated toHash can still be used, whereas if a.opCmp(b) == 0 were
used for opEquals, then toHash would have to be defined.

So, I think that we really should just use the compiler-generate opEquals
unless the programmer defines opEquals themselves, even if opCmp is declared,
and the compiler-generate toHash should be used if the compiler-generated
opEquals is used, whereas it can't be otherwise. The programmer will just have
to make sure that a.opCmp(b) == 0 is equivalent to opEquals if they don't want
bugs. They should be unit testing that anyway.

--


More information about the Digitalmars-d-bugs mailing list