Value type hash code

John Rose john.r.rose at
Wed Apr 11 20:39:43 UTC 2018

On Apr 11, 2018, at 7:13 AM, Dan Smith <daniel.smith at> wrote:
>> On Apr 10, 2018, at 8:49 AM, David Simms <david.simms at> wrote:
>> * Values containing references whose contents are mutable pose a
>>  problem, their hash code is only as stable as the contents of the
>>  whole object graph.
> There's some flexibility in how we name operations, but let's observe that there are two pairs of operations to consider:
> substitutable/substitutableHash: recur on value fields, use acmp on reference fields

Yes.  (And that's a reasonable default.)

> deepEquals/deepHash: recur on value fields, use 'equals' on reference fields

Yes, that's the same as "as if by List.of" I mentioned.

> I think my expectation has been that substitutable/substitutableHash would be the default behavior of equals/hashCode, with the capability for users to override this if they're confident it's safe. (And with the ability to fall back to the default behavior with System.identityHashCode or something similar.)

One can be the default; both should be available as explicit opt-ins (via BSM).

Despite what I said in my previous message, the substitutable one would be a
more conservative choice of default; it corresponds closely to the define behavior
for references.  Reason: acmp/op== is the substitutability test for (possibly stateful)
objects, and that (not deepEquals) is the default for references.

Still, the deepEquals one is probably more useful, for both references and
values, so IMO it should be easy to opt into it.  Note the frequency, for reference
classes, of people having to override Object.equals/hashCode, so their objects
will play well with collection types.  This suggests to me that setting the default
to deepEquals (not substitutable) is a reasonable move to consider.

In the case of "boilerplate friendly" classes like records, deepEquals should be
the default, with an option to revert to the stricter substitutability test by some
other means.  And of course there's a range of possibilities:  If a class has
has two fields, perhaps one should be compared for substitutability and one
for deep equality.  Note that I didn't say whether the class or the fields were
references or values:  The same concerns apply to both.

— John

More information about the valhalla-dev mailing list