<div dir="ltr">Hi Remi,<div>I believe we can stick with bitwise equivalence, at least for now. The bitwise equivalence, in essence, is a remedy for the compatibility issues around == with the removal of identity. Thus, it should not replace and is still not preferable to equals(), even though the migration happens to make == a good implementation in many more cases.</div><div><br></div><div>For a Double object d, there are sets S0 that are all objects with the same identity as d, S1 that are all objects with the same bitwise representation (headers ignored of course) as d, S2 that are all objects with the same representational equivalence as d, and Sequals that are all objects that equals(d). We can see (<= for "is subset of") {d} == S0 <= S1 <= S2 <= (actually ==) Sequals, and whatever the set d == holds true against (call it S==) has S== <= Sequals.</div><div><br></div><div>With the removal of identity, S0 is gone, so S1 becomes S==. What you call for is to use S2 for S==. I believe that the move from S1 to S2 will be a backward-compatible change in the future, but not from S2 to S1. Given the significant performance benefits of using S1 for S== instead of S2, I believe we can stay with the bitwise equivalence and investigate using S2 for S== if the future hardware improvements make it feasible.</div><div><br></div><div>Regards,</div><div>Chen Liang</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Mar 11, 2024 at 8:34 AM Remi Forax <<a href="mailto:forax@univ-mlv.fr">forax@univ-mlv.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Last week, I explain at JChateau (think JCrete in France, less sun, more chateaux) how value types work from the user POV, among other subject describing the semantics of ==.<br>
<br>
First, most of the attendee knew the semantics difference between == on double and Double.equals(). I suppose it's because people that attend to such (un-)conference have a more intimate knowledge of Java than an average developer. Second, no attendee knew that NaN was a prefix.<br>
<br>
So it let me think again on that subject.<br>
<br>
1) The argument that of Dan that we want to be able to create a class with two different NaN, does not hold because instead of storing the values as double, the values can be stored as long.<br>
<br>
value class C {<br>
private double d;<br>
C(double d) { this.d = d; }<br>
long bits() { return Double.doubleToRawLongBits(d); }<br>
}<br>
<br>
C c1 = new C(Double.longBitsToDouble(0x7ff0000000000001L));<br>
C c2 = new C(Double.longBitsToDouble(0x7ff0000000000002L));<br>
assert c1.bits() != c2.bits();<br>
<br>
can be rewritten as<br>
<br>
value class C {<br>
private long l;<br>
C(double d) { this.l = Double.doubleToRawLongBits(d); }<br>
long bits() { return l; }<br>
} <br>
<br>
<br>
2) The de-duplication of value instances by the GC works with both the bitwise equivalence and the representational equivalence.<br>
<br>
If the GC only de-duplicate the value instance based only on the bitwise equivalence, it is a valid algorithm under the representational equivalence.<br>
<br>
<br>
So I not convinced that the bitwise equivalence should be choosen instead of the representational equivalence, for me two semantics instead of three is a win.<br>
<br>
Rémi<br>
</blockquote></div>