<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div class="moz-cite-prefix">On 1/17/2026 5:46 PM, Brian Goetz
wrote:<br>
</div>
<blockquote type="cite" cite="mid:46bd050a-4d6a-41fe-a663-a0c5cd77c766@oracle.com">
<blockquote type="cite" cite="mid:1085557496.17567763.1768646213005.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>With a mutable class with equals/hashCode/toString
generated, it's too easy to store an object in a collection,
mutate it, and then never been able to find it again.</div>
</div>
</blockquote>
<br>
Yes, but also: everyone here knows about this risk. You don't
need to belabor the example :)<br>
<br>
This is a reflection of a problem we already have: equals is a
semantic part of the type's definition, about when two instances
represent the "same" value, and mutability is pat of the type's
definition, and "whether you put it in a hash-based collection and
then mutate it" is about _how the instances are used by
clients_. <br>
<br>
While immutability is a good default, its not always _wrong_ to
use mutability; its just riskier. And for a mutable class,
state-based equality is _still_ a sensible possible implementation
of equality; its just riskier. And putting mutable objects in
hash-based collections is also not wrong; its just riskier. For
the bad thing to happen, all of these have to happen _and then it
has to be mutated_. But if we have to assign primary blame here,
it is not the guy who didn't write `final` on the fields, and not
the guy who said that equality was state-based, but the guy who
put it in the collection and mutated it. <br>
<br>
If we decided that avoiding this risk were the primary design
goal, then we would have to either disallow mutable fields, or
change the way we define the default equals/hashCode behavior.
Potentially ways to do the latter include:<br>
<br>
- never provide a default implementation, inherit the object
default<br>
- don't provide a default implementation if there are any mutable
fields<br>
- leave mutable fields out of the default implementation, but use
the other fields<br>
<br>
While "disallow mutable fields" is a potentially principled
answer, it is pretty restrictive. Of the others, I claim that the
proposed behavior is better than any of them. <br>
<br>
Carrier classes are about data, and come with a semantic claim:
that the state description is a complete, canonical description of
the state. It seems pretty questionable then to use identity
equality for such a class. But the other two alternatives listed
are both some form of "action at a distance", harder to keep track
of, are still only guesses at what the user actually wants. The
two principled options are "don't provide equals/hashCode", and
"state-based equals/hashCode", and of the two, the latter makes
much more sense.<br>
</blockquote>
<p>What about "state-based equals with final fields-based hashCode"?
(Maybe this is actually what you meant with `leave mutable fields
out of the default implementation, but use the other fields`, but
then I don't understand how that's "action at a distance" and
"harder to keep track of".) That would solve the HashSet issue and
be a safe, intuitive default. There might be performance issues
for carrier classes without final fields that are used in large
HashSets, but in that case it's easy enough to provide one's own
implementation of `hashCode`. And by doing so, one would
implicitly consent to the implications of doing so (I could
imagine javac issuing a lint warning for this and/or javadoc
adding a warning to the Javadoc that the carrier class suffers
from the HashSet issue).</p>
<p>Kind regards, Anthony</p>
<blockquote type="cite" cite="mid:46bd050a-4d6a-41fe-a663-a0c5cd77c766@oracle.com">It is
not a bug to put a mutable object in a HashSet; it is a bug to do
that _and_ to later mutate it. So detuning the semantics of
carriers, from something simple and principled to something
complicated and which is just a guess about what the user really
wants, just because someone might do two things that are each
individually OK but together not OK, seems like an
over-rotation. <br>
<br>
</blockquote>
</body>
</html>