A related concern is that many existing uses of == are optimizations
intended to short-circuit evaluation of `equals`, under the assumption
that == is "much faster" than equals. When the performance reality
shifts, some of this code might get slower. (Though in most cases it
probably makes no difference.)
If you assume that most uses of == are accidents, many of them might get
less wrong; for example, using == on Integer (outside of the box cache)
is almost always wrong, but will get less wrong in the future (since it
will compare what's in the box.) This is both better and worse, in that
fewer bugs will manifest as problems, but then bugs may sit undetected
for longer.
(Don't get me started on the "primitives are good for numerics" ->
"numerics will want operator overloading" -> "oh crap, == already means
something" problem.)
On 11/3/2021 11:58 AM, Kevin Bourrillion wrote:
I imagine we might be constrained to this design by the need to
support compatible migration. So there may be nothing we can do.
But there is a pretty serious problem here.
Background: code like IdentityHashMap, which cares about /objects per
se /instead of what those objects /represent/, is unusual,
special-case, egghead, lift-the-caution-tape code. It is not normal.
It's surely more common in JDK code. But I strongly suspect that the
vast majority of `==` tests in the wild are not expressing questions
of identity at all, but are abbreviations for `equals()` when the
developer happens to believe it's safe. Many of those are of course
bugs, and then there are plain accidental usages as well.
Today, things are pretty okay because developers can learn that `==`
is a code smell. A responsible code reviewer has to think through each
one like this:
1. Look up the type. Is it a builtin, or Class? Okay, we're fine.
2. Is it an enum? Okay, I resent having to go look it up when they
could have just used switch, but fine.
3. Wait, is this weird code that actually cares about objects instead
of what they represent? This needs a comment.
The problem is that now we'll be introducing a whole class of ...
classes ... for which `==` does something reasonable: only the ones
that happen to contain no references, however deeply nested! These
cannot at all be easily distinguished. This is giving bugs a really
fantastic way to hide.
I think we'd better consider some heretical options, like introducing
`===` and `!==` as sugar for Object.equals(). It seems tragic to
imagine the entire world (except the special-case code) transitioning
over to that, as it's quite ugly. But it would lead to more
correct code. Maybe you have other ideas.
On Wed, Nov 3, 2021 at 7:05 AM Brian Goetz <brian.go...@oracle.com> wrote:
Extrapolating, ACMP is a _substitutability test_; it says that
substituting one for the other would have no detectable differences.
Because all objects have a unique identity, comparing the
identities is
both necessary and sufficient for a substitutability test.
What you say here may be technically true, but people who override
equals() are already trying their best to disavow identity in the only
way they have. And that makes your statement here actually kinda
/wrong/. Being a necessary and sufficient substitutability test is
literally, exactly, what Object.equals() does (and never mind that
people might implement it /wrong/). If that method's purpose is not to
give classes control over their own substitutability test -- which
they /need!/ -- then I can't imagine a purpose for it at all. (And
yes, those objects still do expose identity, but their equals()
implementation is consenting to have that identity "forgotten" at any
time just by round-tripping it through some collection etc.)
--
Kevin Bourrillion | Java Librarian | Google, Inc. |kev...@google.com