<div dir="ltr"><div class="gmail_default" style="font-family:monospace">Annoying. Piper mail bungled my formatting. Resending, this time with spaces instead of tabs. Yet another reason why spaces are superior to tabs.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Hello Mark,<br><br>Thank you for posting this! I am shocked to see the Level of Effort set to M -- all those sharp edges makes this seem much more complex!<br><br>I was very surprised to see the following snippet in the JEP.<br><br><br>> With pattern labels involving record patterns, some<br>> patterns are considered to be exhaustive even when they<br>> are not unconditional. For example:<br>> <br>> Box<Box<String>> bbs = ...<br>> switch (bbs) {<br>>     case Box(Box(String s)): ...<br>> }<br>> <br>> This switch is considered exhaustive on Box<Box<String>><br>> even though the pattern Box(Box(String s)) will not match<br>> the pathological value new Box(null), which is in the<br>> remainder set and is handled by a synthetic default<br>> clause that throws MatchException.<br>> <br>> With the introduction of primitive type patterns, we<br>> observe that unboxing follows the same philosophy. For<br>> example:<br>> <br>> Box<Integer> bi = ...<br>> switch (bi) {<br>>     case Box(int i): ...<br>> }<br>> <br>> This switch is considered exhaustive on Box<Integer> even<br>> though the pattern Box(int i) will not match the<br>> pathological value new Box(null), which is in the<br>> remainder set.<br><br>This surprises me because it feels like the analogy of Box<Box<String>> is a poor comparison to this. More specifically, it feels like comparing Apples and Oranges.<br><br>The reason I feel that way is because I have a mental model in my head that has the following rules.<br><br>* If I have a top level pattern, it does not match null. That's what case null is for.<br><br>    * For example, case String s, I do not expect s to be null.<br>    <br>        * Because of this, I understand why a case int i would be considered exhaustive, it seems to follow the same rules as a type pattern.<br>        <br>            * And more specifically, the rules of exhaustiveness seem to align here too. If instead of case String s, I had case Foo f, I would assume that the pattern is exhaustive if (f) can match the full domain, not including null.<br><br>* If I have a nested pattern, that pattern can match null.<br><br>    * For example, case Box(String s), I can expect s to maybe be null.<br>    <br>        * Because of this, I do not understand why a case int i would be considered exhaustive, because it seems to break from the rules of a type pattern thus far.<br>        <br>            * To give an example, if I have record Bar(int i), and then I later refactor that to be record Bar(Integer i), I would hope that my type pattern would no longer be exhaustive. But it sounds a lot like the above passage implies it WOULD be exhaustive.<br><br>I do not understand this decision. Could you help me understand the what and the why? I also want to know your response to the sharp corner I raised when it comes to refactoring primitives to and from their boxed variants. Since Valhalla is on its way (hopefully bringing with it the ability to opt-in and opt-out of nullability), it feels like this sharp corner is going to protrude even further and be even sharper. Could you address that concern too please?<br><br>Thank you for your time and help!<br>David Alayachew<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Sep 25, 2023 at 4:50 PM David Alayachew <<a href="mailto:davidalayachew@gmail.com">davidalayachew@gmail.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 dir="ltr"><div class="gmail_default" style="font-family:monospace">Hello Mark,<br><br>Thank you for posting this! I am shocked to see the Level of Effort set to M -- all those sharp edges makes this seem much more complex!<br><br>I was very surprised to see the following snippet in the JEP.<br><br><br>> With pattern labels involving record patterns, some<br>> patterns are considered to be exhaustive even when they<br>> are not unconditional. For example:<br>> <br>> Box<Box<String>> bbs = ...<br>> switch (bbs) {<br>>     case Box(Box(String s)): ...<br>> }<br>> <br>> This switch is considered exhaustive on Box<Box<String>><br>> even though the pattern Box(Box(String s)) will not match<br>> the pathological value new Box(null), which is in the<br>> remainder set and is handled by a synthetic default<br>> clause that throws MatchException.<br>> <br>> With the introduction of primitive type patterns, we<br>> observe that unboxing follows the same philosophy. For<br>> example:<br>> <br>> Box<Integer> bi = ...<br>> switch (bi) {<br>>     case Box(int i): ...<br>> }<br>> <br>> This switch is considered exhaustive on Box<Integer> even<br>> though the pattern Box(int i) will not match the<br>> pathological value new Box(null), which is in the<br>> remainder set.<br><br>This surprises me because it feels like the analogy of Box<Box<String>> is a poor comparison to this. More specifically, it feels like comparing Apples and Oranges.<br><br>The reason I feel that way is because I have a mental model in my head that has the following rules.<br><br>* If I have a top level pattern, it does not match null. That's what case null is for.<br><br>    * For example, case String s, I do not expect s to be null.<br>     <br>          * Because of this, I understand why a case int i would be considered exhaustive, it seems to follow the same rules as a type pattern.<br>           <br>                      * And more specifically, the rules of exhaustiveness seem to align here too. If instead of case String s, I had case Foo f, I would assume that the pattern is exhaustive if (f) can match the full domain, not including null.<br><br>* If I have a nested pattern, that pattern can match null.<br><br>    * For example, case Box(String s), I can expect s to maybe be null.<br>    <br>              * Because of this, I do not understand why a case int i would be considered exhaustive, because it seems to break from the rules of a type pattern thus far.<br>          <br>                      * To give an example, if I have record Bar(int i), and then I later refactor that to be record Bar(Integer i), I would hope that my type pattern would no longer be exhaustive. But it sounds a lot like the above passage implies it WOULD be exhaustive.<br><br>I do not understand this decision. Could you help me understand the what and the why? I also want to know your response to the sharp corner I raised when it comes to refactoring primitives to and from their boxed variants. Since Valhalla is on its way (hopefully bringing with it the ability to opt-in and opt-out of nullability), it feels like this sharp corner is going to protrude even further and be even sharper. Could you address that concern too please?<br><br>Thank you for your time and help!<br>David Alayachew<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Sep 25, 2023 at 10:09 AM Mark Reinhold <<a href="mailto:mark.reinhold@oracle.com" target="_blank">mark.reinhold@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"><a href="https://openjdk.org/jeps/455" rel="noreferrer" target="_blank">https://openjdk.org/jeps/455</a><br>
<br>
  Summary: Enhance pattern matching by allowing primitive type patterns<br>
  to be used in all pattern contexts, align the semantics of primitive<br>
  type patterns with that of instanceof, and extend switch to allow<br>
  primitive constants as case labels. This is a preview language feature.<br>
<br>
- Mark</blockquote></div>
</blockquote></div>