<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>, "amber-spec-experts" <amber-spec-experts@openjdk.java.net><br><b>Sent: </b>Friday, September 12, 2025 7:30:57 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;"><br>
    <br>
    <div class="moz-cite-prefix">On 9/11/2025 11:55 AM, Brian Goetz
      wrote:<br>
    </div>
    <blockquote 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>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>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.  </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><br data-mce-bogus="1"></div>Here are examples (puzzlers) exposing the rift.<div><br></div></div><div data-marker="__QUOTED_TEXT__">  char letter = 'A';</div><div data-marker="__QUOTED_TEXT__">  switch(letter) {</div><div data-marker="__QUOTED_TEXT__">    case short s -> IO.println("short");</div><div data-marker="__QUOTED_TEXT__">    case char c -> IO.println("char");</div><div data-marker="__QUOTED_TEXT__">  }</div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">Here you have a character, typed as a char but it prints "short".</div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">You can write:</div><div data-marker="__QUOTED_TEXT__">  short s = 42;</div><div data-marker="__QUOTED_TEXT__">  switch(s) {</div><div data-marker="__QUOTED_TEXT__">    case char c -> IO.println("char");</div><div data-marker="__QUOTED_TEXT__">    case short s -> IO.println("short");</div><div data-marker="__QUOTED_TEXT__">  }</div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">So when you have a switch with both a char and a short, you have no "right" way to write it.</div><div data-marker="__QUOTED_TEXT__">BTW, why those examples compile is also an interesting question and how can i pattern match on an unsigned int is another good one.</div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">So, yes, it's the semantics of primitive types in it's full glory, but that's a problem because most developers does not rely on the semantics of primitive types in their day to day job,</div><div data-marker="__QUOTED_TEXT__">That the reason why you can write so many puzzlers, because the primitive types semantics is puzzling if the JLS is not your bible.</div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">That why i said that this will be hard to teach, because for my students the primitive type relationship are arcane.</div><div data-marker="__QUOTED_TEXT__">In a way, you and me are from a different generation when saving bits was something important, this is not anymore, JSON does not make a different between int and short.</div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">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 data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">Here is another example:</div><div data-marker="__QUOTED_TEXT__">  record Box<T>(T value) {}</div><div data-marker="__QUOTED_TEXT__">  </div><div data-marker="__QUOTED_TEXT__">  int value = 42;</div><div data-marker="__QUOTED_TEXT__">  switch(new Box<>(value)) {</div><div data-marker="__QUOTED_TEXT__">    case byte b -> IO.println(b);</div><div data-marker="__QUOTED_TEXT__">    case int i -> IO.println(i);</div><div data-marker="__QUOTED_TEXT__">  } </div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">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 data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div><div data-marker="__QUOTED_TEXT__">As a developer, i think i would prefer to be able to write ArrayList<int> than being able to pattern match on primitives with a semantics that only works for primitives.</div><div data-marker="__QUOTED_TEXT__"><br></div><div data-marker="__QUOTED_TEXT__">To summarize, using only primitive types relationship as a semantics for pattern matching on primitive types is not a good idea because Java developers do not care about primitive conversions and it inhibit us to provide more important  features trying to heal the rift between objects and primitives.</div><div data-marker="__QUOTED_TEXT__"> </div><div data-marker="__QUOTED_TEXT__">regards,</div><div data-marker="__QUOTED_TEXT__">RĂ©mi</div><div data-marker="__QUOTED_TEXT__"><br data-mce-bogus="1"></div></div></body></html>