<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<br>
<br>
<div class="moz-cite-prefix">On 9/11/2025 11:55 AM, Brian Goetz
wrote:<br>
</div>
<blockquote type="cite" cite="mid:ddc28d8b-6487-41b1-9c4d-4b6b02154ff2@oracle.com"><br>
I explicitly asked you to answer a question on the semantics when
these conversions were NOT involved before we moved onto these,
because I think you are conflating two separate things, and in
order to get past just repeating "but...lossy!", we have to
separate them.
<br>
</blockquote>
<br>
<font size="4" face="monospace">I see Remi has lost interest in this
discussion, so I will play both parts of the dialogue on his
behalf now. <br>
<br>
<blockquote type="cite">Let's start with the easy ones:
<br>
<br>
Object p = "foo"; // widen String to Object
<br>
Object q = Integer.valueOf(3) // widen Integer to Object
<br>
...
<br>
if (p instanceof String s) { ... } // yes it is
<br>
if (q instanceof String s) { ... } // no it isn't
<br>
<br>
We can widen String and Integer to Object; we can safely narrow
p back to String, but we can't do so for q, because it is
"outside the range" of references to String (which embeds in
"references to Object".) Does this make sense so far? <br>
</blockquote>
<br>
Remi: It has always been this way. <br>
<br>
<blockquote type="cite">OK, now let's do int and long.
<br>
<br>
long small = 3
<br>
long big = Long.MAX_VALUE
<br>
<br>
if (small instanceof int a) { ... } // yes, it is
<br>
if (big instanceof int b) { ... } // no, it isn't
<br>
<br>
What these questions are asking is: can I safely narrow these
longs to int, just like the above. In the first case, I can --
just like with String and Object. In the second, I can't --
just like with Integer and Object. Do we agree these are the
same?<br>
</blockquote>
<br>
Remi: Yes Socrates, I believe they are. <br>
<br>
<blockquote type="cite">OK, now let's do int and double.
<br>
<br>
double zero = 0;
<br>
double pi = 3.14d;
<br>
<br>
if (zero instanceof int i) { ... }
<br>
if (pi instanceof int i) { ... }
<br>
<br>
Same thing! The first exactly encodes a number that is
representable in int (i.e., could have arisen from widening an
int to double), the latter does not. <br>
</blockquote>
<br>
Remi: It could be no other way, Socrates.<br>
<br>
But we can replace double with float in the previous example, and
nothing changes:<br>
<br>
<blockquote type="cite"><font size="4" face="monospace"> float
zero = 0; <br>
float pi = 3.14f; <br>
<br>
if (zero instanceof int i) { ... } <br>
if (pi instanceof int i) { ... } <br>
</font></blockquote>
<br>
Here, we are asking a sound question: does the number encoded in
this `float` exactly represent an `int`. For `zero`, the answer
is "of course"; for `pi`, the answer is "obviously not."<br>
<br>
Remi: Yes, Socrates, that is clearly evident.<br>
<br>
<br>
I'm now entering guessing territory here, but I'm pretty sure I
understand what's making you uncomfortable. But, despite the
clickbaity headline and misplaced claims of wrongness, this really
has nothing to do with pattern matching at all! It has to do with
the existing regrettable treatment of some conversions (which we
well understood are problematic, and are working on), and the fact
that by its very duality, pattern matching _exposes_ the
inconsistency that while most "implicit" conversions (more
precisely, those allowed in method and assignment context) are
required to be "safe", we allow several lossy conversions in these
contexts too (int <--> float, long <--> float, long
<--> double). (The argument then makes the leap that
"because this exposes a seeming inconsistency, the new feature
must be wrong, and should be changed." But it is neither fair nor
beneficial to blame the son, who is actually doing it right, for
the sins of the fathers.) <br>
<br>
In other words, you see these two cases as somehow so different
that we should roll back several years of progress just to avoid
acknowledging the inconsistency:<br>
<br>
float f = 0;<br>
if (f instanceof int i) { ... }<br>
<br>
and<br>
<br>
float g = 200_000_007; // lossy <br>
if (g instanceof int i) { ... }<br>
<br>
because in the first case, we are merely "recovering" the int-ness
of something that was an int all along, but in the second case, we
are _throwing away_ some of the int value and then trying to
recover it, but without the knowledge that a previous lossy
operation happened. <br>
<br>
But blaming pattern matching is blaming the messenger. Your beef
is with the assignment to g, that we allow a lossy assignment
without at least an explicit cast. And this does seem
"inconsistent"! We generally go out of our way to avoid lossy
conversions in assignments and method invocation (by allowing
widening conversions but not narrowing ones) -- except that the
conversion int -> float is considered (mystifyingly) a
"widening conversion." <br>
<br>
Except there's no mystery. This was a compromise made in 1995
borne of a desire for Java to not seem "too surprising" to C
programmers. So this conversion (and two of its irresponsible
friends) were characterized as "widenings", when in fact they are
not. <br>
<br>
If I could go back to 1995 and argue against this, I would. But I
can't do that. What I can do is to acknowledge that this was a
regrettable misuse of the term widening, and not extrapolate from
this behavior. Can we change the language to disallow these
conversions in assignment and method context? Unlikely, that
would break way too much code. We can, though, clarify the
terminology in the JLS, and start to issue warnings for these
lossy implicit conversions, and instead encourage an explicit cast
to emphasize the "convert to float, dammit" intentions of the
programmer (which is what we plan to do, we just haven't finalized
this plan yet.) But again, this has little to do with the proper
semantics of pattern matching; it is just that pattern matching is
the mirror that reveals the bad behavior of existing past mistakes
more clearly. It would be stupid to extrapolate this mistake
forward into pattern matching -- that would make it both more
confusing and more complicated. Instead, we admit our past
mistakes and improve the language as best as we can. In this
case, there was a pretty good answer here, despite the legacy
warts. <br>
<br>
Before I close this thread, I need to reiterate that just because
there is a seeming inconsistency, this is not necessarily evidence
that the _most recent move_ is a mistake. So next time, if you
see an inconsistency, instead of thumping your shoe on the table
and crying "mistake! mistake!", you could ask these questions
instead:<br>
<br>
- This seems like an inconsistency, but is it really?<br>
- If this is an inconsistency, does that mean that one case or
the other is mistake? <br>
- If there is a mistake, can it be fixed? If not, should we
consider changing course to avoid confusion, or are we better off
living with a small inconsistency to get a greater benefit?<br>
<br>
These are the kinds of questions that language designers grapple
with every day. <br>
<br>
<br>
</font>
</body>
</html>