New candidate JEP: 455: Primitive types in Patterns, instanceof, and switch (Preview)
David Alayachew
davidalayachew at gmail.com
Tue Sep 26 03:51:49 UTC 2023
On a side note, are there any builds of EA Java 22 that have this
implemented yet? Or is it still not available?
On Mon, Sep 25, 2023 at 11:50 PM David Alayachew <davidalayachew at gmail.com>
wrote:
> Hello Brian,
>
> Thank you for your response!
>
> > Imagine it worked the way your intuition tells you it
> > should work. I'll start with the old case, nested record
> > patterns. Now, suppose you have:
> >
> > record Pair<T,U>(T t, U u) { }
> >
> > ...
> >
> > Pair<Pair<A, B>, Pair<C, D>> p = ...
> >
> > switch (p) {
> > case Pair(Pair(A a, B b), Pair(C c, D d)): ...
> > }
> >
> > Under the David rules, this switch is not exhaustive,
> > because it matches neither Pair(null, _) or
> > Pair(_, null). So what cases would you have to add to the
> > switch to satisfy the compiler's complaints of
> > non-exhaustiveness? Write the code, and then tell me if
> > you want to program in that language...
>
> Excellent example lol. That clarifies it perfectly. So, the reason why we
> do not want to have this level of specificity required by the programmer is
> because it would cascade into a giant pile of writing down edge cases.
> Makes perfect sense.
>
> > The first part of the example (Box<Box<String>>) is not
> > new to this JEP; this is how nested patterns work. (If
> > you think about it for long enough, you realize that the
> > alternatives are all nearly intolerable.) The
> > Box<Integer> example just adds one more form of
> > remainder.
>
> I always try and think these questions through before asking them, but
> there's only so far my brain can stretch without trying things out myself.
> Thank you very much.
>
> > The gap between exhaustiveness and totality (which we
> > call "remainder") is indeed somewhat counterintuitive at
> > first, because we would like for these two words to mean
> > the same thing. There were many, many discussions
> > regarding this in Record Patterns. This JEP extends the
> > surprise a little bit, but only in a quantitative, not
> > qualitative way; unboxing conversions are another place
> > where we encounter a gap between these two similar
> > concepts.
>
> That word "Remainder" reminds me now. It looks like my exact question was
> already answered in the "Remainder" doc from a few months ago.
>
>
> https://openjdk.org/projects/amber/design-notes/patterns/exhaustiveness#nested-patterns-and-sealed-types
>
> In my defense though, that doc was pretty content-dense, full of
> explaining how the unintuitive is better than the alternative.
>
> I guess another take away from this exchange is recognizing that what I
> have been looking at this entire time is called the "Remainder". Knowing
> that gives me a cue to start watching for nulls, as well as other possible
> remainders.
>
> Thank you for your time and help!
> David Alayachew
>
> On Mon, Sep 25, 2023 at 8:07 PM Brian Goetz <brian.goetz at oracle.com>
> wrote:
>
>> The gap between exhaustiveness and totality (which we call "remainder")
>> is indeed somewhat counterintuitive at first, because we would like for
>> these two words to mean the same thing. There were many, many discussions
>> regarding this in Record Patterns. This JEP extends the surprise a little
>> bit, but only in a quantitative, not qualitative way; unboxing conversions
>> are another place where we encounter a gap between these two similar
>> concepts.
>>
>> The first part of the example (Box<Box<String>>) is not new to this JEP;
>> this is how nested patterns work. (If you think about it for long enough,
>> you realize that the alternatives are all nearly intolerable.) The
>> Box<Integer> example just adds one more form of remainder.
>>
>> Imagine it worked the way your intuition tells you it should work. I'll
>> start with the old case, nested record patterns. Now, suppose you have:
>>
>> record Pair<T,U>(T t, U u) { }
>>
>> ...
>>
>> Pair<Pair<A, B>, Pair<C, D>> p = ...
>>
>> switch (p) {
>> case Pair(Pair(A a, B b), Pair(C c, D d)): ...
>> }
>>
>> Under the David rules, this switch is not exhaustive, because it matches
>> neither Pair(null, _) or Pair(_, null). So what cases would you have to
>> add to the switch to satisfy the compiler's complaints of
>> non-exhaustiveness? Write the code, and then tell me if you want to
>> program in that language...
>>
>>
>>
>>
>>
>> On 9/25/2023 4:50 PM, David Alayachew wrote:
>>
>> Hello Mark,
>>
>> 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!
>>
>> I was very surprised to see the following snippet in the JEP.
>>
>>
>> > With pattern labels involving record patterns, some
>> > patterns are considered to be exhaustive even when they
>> > are not unconditional. For example:
>> >
>> > Box<Box<String>> bbs = ...
>> > switch (bbs) {
>> > case Box(Box(String s)): ...
>> > }
>> >
>> > This switch is considered exhaustive on Box<Box<String>>
>> > even though the pattern Box(Box(String s)) will not match
>> > the pathological value new Box(null), which is in the
>> > remainder set and is handled by a synthetic default
>> > clause that throws MatchException.
>> >
>> > With the introduction of primitive type patterns, we
>> > observe that unboxing follows the same philosophy. For
>> > example:
>> >
>> > Box<Integer> bi = ...
>> > switch (bi) {
>> > case Box(int i): ...
>> > }
>> >
>> > This switch is considered exhaustive on Box<Integer> even
>> > though the pattern Box(int i) will not match the
>> > pathological value new Box(null), which is in the
>> > remainder set.
>>
>> 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.
>>
>> The reason I feel that way is because I have a mental model in my head
>> that has the following rules.
>>
>> * If I have a top level pattern, it does not match null. That's what case
>> null is for.
>>
>> * For example, case String s, I do not expect s to be null.
>>
>> * 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.
>>
>> * 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.
>>
>> * If I have a nested pattern, that pattern can match null.
>>
>> * For example, case Box(String s), I can expect s to maybe be null.
>>
>> * 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.
>>
>> * 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.
>>
>> 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?
>>
>> Thank you for your time and help!
>> David Alayachew
>>
>> On Mon, Sep 25, 2023 at 10:09 AM Mark Reinhold <mark.reinhold at oracle.com>
>> wrote:
>>
>>> https://openjdk.org/jeps/455
>>>
>>> Summary: Enhance pattern matching by allowing primitive type patterns
>>> to be used in all pattern contexts, align the semantics of primitive
>>> type patterns with that of instanceof, and extend switch to allow
>>> primitive constants as case labels. This is a preview language feature.
>>>
>>> - Mark
>>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/jdk-dev/attachments/20230925/46135798/attachment.htm>
More information about the jdk-dev
mailing list