Value object equality & floating-point values
Clement Cherlin
ccherlin at gmail.com
Mon Feb 12 20:09:59 UTC 2024
On Fri, Feb 9, 2024 at 12:56 PM Dan Smith <daniel.smith at oracle.com> wrote:
>
> On Feb 9, 2024, at 10:13 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>
> value class C {
> private double d;
> C(double d) { this.d = d; }
> long bits() { return Double.doubleToRawLongBits(d); }
> }
>
> C c1 = new C(Double.longBitsToDouble(0x7ff0000000000001L));
> C c2 = new C(Double.longBitsToDouble(0x7ff0000000000002L));
> assert c1.bits() != c2.bits();
>
> Will this assert ever fail? Well, it depends on the JVM treats c1 and c2 as belonging to the same equivalence class. If they are, it's allowed to substitute c1 for c2 at any time. I think it's pretty clear that would be a mistake.
>
>
> I do not compute that statement :)
>
> Why do you want users to care about the bitwise representation of NaN ?
> Both 0x7ff0000000000001L and 0x7ff0000000000002L represents NaN, if we print c1.d and c2.d both will print NaN, if we use c1.d or c2.d in numeric computation, they will both behave as NaN.
>
>
> To be very specific about this example, I think it's bad if the result of the 'c.bits()' method is nondeterministic, making the 'assert' result unpredictable.
>
> Two instances of C with representationally-equivalent state can produce different results from their 'c.bits()' method. So they aren't substitutable (per the "can substituted for one another without changing the result of the expression" definition). I would be uncomfortable with the JVM substituting one for the other whenever it wants to.
>
> Sure, the *native* operations on *double* almost never distinguish between different NaN encodings. But a *custom* operation on *a class that wraps a double* certainly can.
>
> (The example could be improved by doing a better job of illustrating that the double is private internal state, and that the operations exposed by the class need not look at all like floating-point operations, as far as the client of the class is concerned. All they know is they've got an object that is randomly producing nondeterministic results.)
>
> This, by itself, is not an argument for '==' being defined to use bitwise equivalence, but it is an argument for a well-defined concept of "substitutable value object" that is based on bitwise equivalence.
>
> Using your example, but with a value record (supposing the bitwise equivalence)
>
> value record C(double d) { }
> C c1 = new C(Double.longBitsToDouble(0x7ff0000000000001L));
> C c2 = new C(Double.longBitsToDouble(0x7ff0000000000002L));
>
> System.out.println(c1); // C[d=NaN]
> System.out.println(c2); // C[d=NaN]
> System.out.println(c1 == c2); // false ??
> System.out.println(c1.equals(c2)); // true
>
>
> Sure. I mean, this is the exact same result as you get with an identity record, so I don't think it should be surprising. The fallacy, I think, is in expecting '==' for value objects to be something more than a substitutability test. (Which, like I said, could be done, but it seems like a distraction when what you really want to use is 'equals'.)
>
> Compare:
>
> value record S(String s) {}
> S s1 = new S("abc");
> S s2 = new S("abcd".substring(0,3));
>
> System.out.println(s1); // S[s=abc]
> System.out.println(s2); // S[s=abc]
> System.out.println(s1 == s2); // false
> System.out.println(s1.quals(s2)); // true
>
> This may be a new concept to learn: value objects with double fields can be 'equals' but not '==', just like value objects with reference fields can be 'equals' but not '=='. But I think that's a better quirk to learn than '==' sometimes not meaning "substitutable".
Question:
What is the proposed behavior of == between Double values in Valhalla?
I hope it's consistent with other value classes that have double
fields.
Commentary:
I'd prefer for == to compare value class float/double fields using
canonical equivalence, same as .equals(), rather than raw bitwise.
However, I'll grudgingly accept "raw" equality as long as it's
consistent across the board and Float/Double don't receive special
treatment.
Cheers,
Clement Cherlin
More information about the valhalla-spec-observers
mailing list