Implementation of == and Object::equals

Remi Forax forax at univ-mlv.fr
Tue Apr 9 11:09:21 UTC 2024


> From: "John Bossons" <jbossons at gmail.com>
> To: "valhalla-dev" <valhalla-dev at openjdk.org>
> Sent: Monday, April 8, 2024 4:30:44 AM
> Subject: Implementation of == and Object::equals
Hi John, 
adding to what Roger said, 

> I'm not sure that this is the right place to raise this, but don't know where
> else to do so.
> For identity types, == is simply a test of reference equality and so is a useful
> first test in an overriding type-specific equals method.

No, it's a bad idea performance-wise. 
see https://youtu.be/kuzjX_efuDs?list=PLX8CzqL3ArzV4BpOzLanxd4bZr46x5e87 

> For value types, the relationship is more subtle, since == is a test of value
> equality, not reference equality. I suggest it be implemented as an operator
> causing Object::equals to be invoked, so that if Object::equals is overloaded
> (e.g. to first test equality of hash codes or otherwise modify the default
> equals test), the overloaded method is automatically invoked when == is used.

> This would mean that Object::equals implements the == operator, rather than the
> reverse, so that a specification that a == b always means a.equals(b), whether
> implemented by the default test or by an overriding type-specific method (that
> e.g. tests for equality of identity object field values). I believe this would
> make value types (especially value trees) easier to use.

Two things, (1) the semantics of equals() on a class (value or identity) is stronger than the semantics of == on a value class, (2) what you propose introduce a circularity between == and equals, so if equals itslef uses ==, it's an infinite loop. 

Imagine you have a value class defined like this: 
value class MyValueClass { 
String s; 

public boolean equals(Object o) { 
return o instanceof MyValueClass other && s.equals(other.s); 
} 
} 

1) calling == on an instance of MyValueClass should check if s == other.s, not calling s.equals(other.s) on the field "field" so the semantics of == is different from the semantics of equals. 

2) if we write equals like that and == calls equals() 
public boolean equals(Object o) { 
return this == o && o instanceof MyValueClass v && field.equals(v.field); 
} 

we have an infinite loop. 

That's why == on value type is defined as doing == on each field and not as calling equals on each field. 

That's said, in the future, for some value types, we may let users to be able to override == and identity hashCode so anyone can write it's own primitive type, but it will not be the default behavior and we are not there yet. 

> John

regards, 
Rémi 

> --
> Phone: (416) 450-3584 (cell)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-dev/attachments/20240409/95a2672b/attachment.htm>


More information about the valhalla-dev mailing list