Yes, it's a tempting direction. John and I both walked that road, in
the hope that there was a reasonable place to cut off the regress. (And
we both walked back disappointed.)
One problem is that with erased generics, all Ts become Object:
/* erased */ value class Box<T> {
T t;
}
translates to
value class Box {
Object t;
}
So no two boxes would be == to each other -- in fact, a given Box would
not be == to itself. I think users would find
Optional<Point> o = Optional.of(p);
o == o // false
to be surprising! Similarly, classes like
value record Twople<T,U>(T t, U u);
Twople<String, String> x = new Twople("a", "b"),
y = x;
x == x // false
x == y // false
Whereas the non-generic version:
value record TwoStrings(String a, String b);
TwoStrings x = new TwoStrings("a", "b"),
y = x;
x == x // true
x == y // true
So I think what this does is just move the surprise to where you don't
trip over it 100% of the time, but you still trip often enough that you
curse it.
On 2/20/2019 3:33 PM, Remi Forax wrote:
I still think we have not finished exploring how to implement acmp for value
types.
We currently have two semantics for value types:
- always return false,
- recursively compare each components
Support of acmp like the support of synchronized or System.identityHashcode is
not a part of the original model where we can just say, it should work like an
int because it's a consequence of lworld, making value types subtypes of
Object, not something inherent to the concept of value types. or said
differently, if it should work like an int, a == on value types at Java level
should be converted to a vcmp (like there is an icmp_*) which is not an answer
to how acmp is supposed to work.
The issue with the first semantics is that it will be very surprising and will
not be compatible with all the existing codes that only use == instead of a ==
followed by a call to equals().
The issue with the second semantics is that it's an unbounded computation,
shaking the Java performance model everybody has in mind by moving == from one
of the fastest operation to a potentially very slow operation.
I wonder if there is not a intermediary semantics, return false if one field is
an Object or an interface or do a component wise comparison otherwise ?
For value types like Point, Complex, == is the component wise comparison, for a
value type that works like Optional, == return false.
It seems not that bad but it means that doing an == on a wildcard of a reified
generics like Atomic<T> depends on the class of T at runtime ?
Rémi