<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Brian Goetz" <brian.goetz@oracle.com><br><b>To: </b>"Remi Forax" <forax@univ-mlv.fr><br><b>Cc: </b>"amber-spec-experts" <amber-spec-experts@openjdk.java.net><br><b>Sent: </b>Wednesday, September 17, 2025 2:12:09 PM<br><b>Subject: </b>Re: Type primitive pattern: the problem with lossy conversions<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><blockquote cite="mid:1693247182.30917300.1758091043726.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><font size="4" face="monospace"><blockquote><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. </font></blockquote>
<div><br>
</div>
<div>No, they are not.</div>
<div>When you widen an Integer to an Object, it stays an
Integer at runtime, when you widen an int to a long, you
transform it to a long, the original int is lost.</div>
</div>
</div>
</blockquote>
<br>
Lost? Numbers can be lost? OMG, that's terrible! Can you imagine
if we lost a _really_ important number, like one or zero? Society
would collapse. Something must be done!</blockquote><div><br></div><div><div><br></div><div>Okay, wrong wording, what i wanted to say is the original fact that the value was an int is lost.</div><div>Not the value itself, my bad on that.</div></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<br>
Oh, wait, that's not how it works. Numbers, being platonic ideals,
just ARE. I can summon zero into being at will:<br>
<br>
int a = 0;<br>
<br>
Can I summon multiple zeroes? Let me try: <br>
<br>
int a = 0;<br>
int b = 0;<br>
<br>
No, I can't, they are the same zero. I cannot discern any
difference between the zero in a and the zero in b (this is the
"substitutibility" criteria on which Valhalla equality is based.) <br>
<br>
If I put zero in an int, and then move it to a long, and back, can I
tell the difference? <br>
<br>
int a = 0;<br>
long b = a;<br>
int c = (int) b;<br>
<br>
No, I cannot; the zero in a and the zero in c are the same value.
And -- crucially -- the zero in *b* is not a "different zero". This
concept has been embedded in the JLS forever. JLS 4.2 defines byte,
short, int, and long as binary encodings of _integers_. </blockquote><div><br></div><div>yes, </div><div>what i wanted to say is that the type is lost,.</div><div><br data-mce-bogus="1"></div><div>In the substitutibility test of Valhalla, the type is check first so there is no issue,</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<br>
Did we *have* to do this right now? No, we didn't; we could have
continued to allow pattern matching on primitives to be invariant,
at least for a while. But that would be increasingly problematic as
Valhalla adds new numeric types; we'd be able to convert them via
assignment, but not ask if they are the same. Similarly, it would make constant patterns more difficult. </blockquote><div><br></div><div>There is another alternative to the pattern matching on primitives being invariant,</div><div>o instanceof Foo foo can be o.getClass() == Foo.class && o == foo.</div><div><br data-mce-bogus="1"></div><div>It works fir const</div><div><br></div><div>I agree, if this JEP is included in Java, yes, we will also have to support value type with witness conversions in pattern matching too.</div><div>But for me, it's an argument against rushing to release this JEP.</div><div>I would like to be sure that allowing such conversions in between value classes in pattern matching is a good idea or not given that the conversion are user defined (not JLS defined).</div><div><br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br></blockquote><div><br></div><div><br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<br>
Your puzzlers -- like the objection about lossy conversions -- are
not about pattern matching, they are merely that pattern matching
reveals existing decisions about the language that we might not, in
hindsight, like. <br>
<br>
<blockquote cite="mid:1693247182.30917300.1758091043726.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>Here are examples (puzzlers)
exposing the rift.
<div><br>
</div>
</div>
<div> char letter = 'A';</div>
<div> switch(letter) {</div>
<div> case short s ->
IO.println("short");</div>
<div> case char c ->
IO.println("char");</div>
<div> }</div>
<div><br>
</div>
<div>Here you have a character,
typed as a char but it prints "short".</div>
</div>
</blockquote>
<br>
Your objection here is that that `char` is not really a character
type, it is a 16 bit signed integral type, with support for literals
that look like characters. But Java will freely convert between
characters and other integral types; this is your objection, and
pattern matching merely makes it more obvious. Same with your other
example.<br>
<br>
<blockquote cite="mid:1693247182.30917300.1758091043726.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>Moreover, with Valhalla, we
want to try to make primitive to looks more like value class,
we talk about by example allowing ArrayList<int> as an
example, but this goal is in conflict with the semantics of
the primitive type pattern JEP, because the JEP semantics is
based on a world where primitives and objects do not talk to
each others.</div>
</div>
</blockquote>
<br>
A better way to think about this is that this JEP is preparing the
way for pattern matching on values. When Valhalla is complete, the
world of references and primitives will give way to one of identity
objects and value objects. Identity objects get their polymorphism
through inheritance (which is transitive); value objects get their
polymorphism through point-to-point conversions. This JEP takes the
first step by providing a unified framework for type patterns, based
on the set of conversions permitted in cast context (the most
permissive set of conversions), and the notion of _exact conversion_
(was the conversion lossy or not.) This sets the stage for pattern
matching in Valhalla. <br>
<br>
<blockquote cite="mid:1693247182.30917300.1758091043726.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>Here is another example:</div>
<div> record Box<T>(T
value) {}</div>
<div> </div>
<div> int value = 42;</div>
<div> switch(new
Box<>(value)) {</div>
<div> case byte b ->
IO.println(b);</div>
<div> case int i ->
IO.println(i);</div>
<div> } </div>
<div><br>
</div>
<div>This one does no compile
because the int value is automatically auto-promoted to an
Integer, which follows different rules than the primitive
rules (per this JEP).</div>
</div>
</blockquote>
<br>
I'm not sure what your objection is, but like the other examples, I
am sure it has nothing to do with pattern matching. The semantics
of switch are defined relative to the selector expression, the value
and type of which has nothing to do with the patterns in the body of
the switch. `new Box<>(value)` is an expression with its own
type; we can then match on it with patterns that are applicable to
that type. Whether or not we can express primitive type patterns
doesn't affect the typing of the selector. <br>
<br>
Your claim that this "inhibits" the unification of objects and
primitives is a very big one. Go take as much time as you need to
capture this argument clearly and persuasively. <br>
<br>
<br><br></blockquote></div></div></body></html>