<div dir="ltr"><div dir="ltr"><div>Hi Dan and Remi,</div>In addition to Dan's reference pointer example, which I strongly agree with, I wish to share another example that more closely aligns with the existing double or float: OptionalInt.<div><br></div><div>OptionalInt has 2 fields: boolean isPresent and int value. However, not all possible combinations of the 2 fields are usually used; like NaN has many representations, the absent value has many representations (its value field can take any int value).</div><div><br></div><div>When we have an OptionalInt(false, 0) and an OptionalInt(false, 1), should we have == stand true for them? No, even though their behaviors are the same otherwise.</div><div><br></div><div>"But OptionalInt's constructor prevents these values!" One might argue. We wish that double had constructors that prevented creation of distinct NaNs, too, as it is not a cartesian product of its components.</div><div><br></div><div>Even though we must live with this vestige of positive and negative zero and many types of infinity and the special == operator logic for double, I don't think it's a convincing argument for us to complicate the object == logic to support non-cartesian values in corner-case states to be the same as their "normal" states. We now have constructors to normalize and sanitize input values if you really love ==, so the OptionalInt scenario never happens in practice; nothing prevents you from normalizing the double values you write to your strict fields, and you can move on to use == as you please.</div><div><br></div><div>Regards,</div><div>Chen Liang</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Feb 9, 2024 at 12:56 PM Dan Smith <<a href="mailto:daniel.smith@oracle.com">daniel.smith@oracle.com</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">



<div>
<div>
<blockquote type="cite">
<div>On Feb 9, 2024, at 10:13 AM, Remi Forax <<a href="mailto:forax@univ-mlv.fr" target="_blank">forax@univ-mlv.fr</a>> wrote:</div>
<div><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
</div>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">value class C {<br>
   private double d;<br>
   C(double d) { this.d = d; }<br>
   long bits() { return Double.doubleToRawLongBits(d); }<br>
}</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">C c1 = new C(Double.longBitsToDouble(0x7ff0000000000001L));<br>
C c2 = new C(Double.longBitsToDouble(0x7ff0000000000002L));<br>
assert c1.bits() != c2.bits();<br>
<br>
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.</blockquote>
</blockquote>
<blockquote type="cite">
<div><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
<span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;float:none;display:inline">I
 do not compute that statement :)</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
<br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
<span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;float:none;display:inline">Why
 do you want users to care about the bitwise representation of NaN ?</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
<span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;float:none;display:inline">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.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none">
</div>
</blockquote>
<div><br>
</div>
<div>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.</div>
<div><br>
</div>
<div>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.</div>
<div><br>
</div>
<div>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.</div>
<div><br>
</div>
<div>(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.)</div>
<div><br>
</div>
<div>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.</div>
<div><br>
</div>
<div>
<blockquote type="cite">Using your example, but with a value record (supposing the bitwise equivalence)<br>
<br>
value record C(double d) { }<br>
C c1 = new C(Double.longBitsToDouble(0x7ff0000000000001L));<br>
C c2 = new C(Double.longBitsToDouble(0x7ff0000000000002L));<br>
<br>
System.out.println(c1);  // C[d=NaN]<br>
System.out.println(c2);  // C[d=NaN]<br>
System.out.println(c1 == c2);  // false ??<br>
System.out.println(c1.equals(c2));  // true<br>
</blockquote>
<br>
</div>
<div>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'.)</div>
<div><br>
</div>
<div>Compare:</div>
<div><br>
</div>
<div>value record S(String s) {}</div>
<div>S s1 = new S("abc");</div>
<div>S s2 = new S("abcd".substring(0,3));</div>
<div><br>
</div>
<div>System.out.println(s1); // S[s=abc]</div>
<div>System.out.println(s2); // S[s=abc]</div>
<div>System.out.println(s1 == s2); // false</div>
<div>System.out.println(s1.quals(s2)); // true</div>
<div><br>
</div>
<div>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".</div>
<div><br>
</div>
</div>
</div>

</blockquote></div></div>