3 ms·
Yes, that's why I was recommending that the default implementation be a compiler-generated member-by-member non-reference comparison, with the option to overrid
by kstenerud 7y ago
Yes, that's why I was recommending that the default implementation be a compiler-generated member-by-member non-reference comparison, with the option to override that behavior by providing your own custom implementation of equals(). Then you get the intuitive result for the 80% case, and have the means to write custom code for the other 20%. Not having an equals in the root object makes equality checks on type-erased values impossible because there would be no standard, reliable way to do it (C++ solved this with operator overloads).
hashCode, on the other hand, would have been better as an interface so that the developer is forced to think about how it gets generated (because a default implementation is more likely to get it wrong than right). The Map classes, for example, would only accept key values that implement Hashable.
- lazulicurio 7y agoWhat I was trying to get across with my example was that you can define a standard, reliable way to perform equality checks on type-erased values without having equals on the root object. Granted, it looks a bit wonky, but it provides safer behavior than an instance equality method.
- kstenerud 7y agoI understand, but the issue here is with making a fundamental operation (equality) an optional interface, which would make things unnecessarily complicated for the user. We always need the ability to check for equality, regardless of type (so much so that we have an "=" operator). The trouble comes with deciding what equality even means (as this article pointed out), because it really depends on the types you're comparing. C++ decided that the best way to solve it would be to allow operator overloading. Unfortunately, overloading "=" worked so well that they thought "Hey! We could do the same for ALL operators!", and the mess that is C++ operator overloading was born. The Java folks figured that they'd learned from C++ mistakes, and would avoid them by forbidding operator overloading entirely, thus throwing the baby out with the bathwater (and also they cheated because the "+" operator is overloaded for strings). What they should have done is simply allowed overloading of the "=" operator ONLY, then maybe also add a special notation to say "I mean the actual reference (i.e. pointer value) as opposed to the object contents" (to cover the 20% use case where you actually DO want to know if it's the same reference). This would have obviated the need for equals(), made "=" work the way you'd intuitively expect it to, and also allowed implementors to override the default implementation to "do the right thing", even when you don't know the type of the values you are comparing (for example after fetching from an untyped collection).
- renox 7y ago>and also they cheated because the "+" operator is overloaded for strings Which isn't a good idea IMHO, in most case a + b == b + a.. Also using a different operator for concatenation (say ~ like D) allow unambiguous array-extension of these operation: a[]+b[] is element by element addition and a[]~b[] is concatenation.