Pattern Matching for switch (Second Preview)
Gavin Bierman
gavin.bierman at oracle.com
Thu Sep 30 12:25:14 UTC 2021
On 22 Sep 2021, at 20:25, Brian Goetz <brian.goetz at oracle.com<mailto:brian.goetz at oracle.com>> wrote:
I have several things I'd like to see make it into this round.
1. Totality for GADTs. If we have a hierarchy:
sealed interface Foo<T> { }
class A<T> implements Foo<T> { }
class B<T> implements Foo<T> { }
class C implements Foo<String> { }
then when switching over a Foo<String>, we need all of A/B/C to be total, but when switching over a Foo<Shoe>, we only need cover A and B in order to be total, because C is not a possible choice. When considering totality, we should only consider the options whose parameterizations are consistent with that of the target.
Yes, we’re working on this. Hope to have something real soon.
2. Inference for type patterns. This one may be a little controversial, because we already let this ship sail with type patterns in instanceof, but I'm pretty convinced that what we're doing right now is wrong. Currently, if we are switching on a List<String>, we disallow a type pattern for ArrayList<Frog>, because this would require an unchecked conversion. This is right. But if we have a `case ArrayList a`, the type of `a` is not ArrayList<String>, but raw ArrayList. This is almost always not what the user wants; there's no migration compatibility here where the switch target was generified but the case labels are not. Like we do with method references, we should infer a reasonable parameterization of ArrayList from the match target when a "naked" type shows up in a type pattern. (If the user really wants a raw ArrayList, they can switch on a raw List.)
Fixing this for switch is no problem, as it is in preview, but fixing this in instanceof requires more care, since there may be production code out there. However, we've generally held that it is OK to infer _more_ specific types than have previously been inferred; I doubt much code would be impacted -- more likely, some silly casts would go away, since users no longer have to cast to ArrayList<String>.
I’m still unsure about this. Type patterns are treated like variable declarations - indeed we went to *a lot* of effort to harmonise all treatments in the JLS regarding variable declarations. What we got to was very pleasing - even if I say so myself - pattern variable declarations are just variable declarations with a special treatment for scope. This proposal will break that because now when a user declares a pattern variable of type ArrayList they get something else. Would we not prefer some sort of indication from the user that they want inference here? What if they do want the raw type?
3. Also, Dan raised a coverage question here:
https://mail.openjdk.java.net/pipermail/amber-spec-experts/2021-July/003049.html
In this example (asterisk means abstract):
A* = B1* | B2* | C*
B1* = D1
B2* = D2
C* = D1 | D2
In order to cover A, we need to cover B1|B2|C. Given
case B1:
case B2:
B1 and B2 are clearly covered; the question is C. And C=D1|D2. B1 covers D1, and B2 covers D2, so B1|B2 covers D1|D2, and therefore B1|B2 covers C.
Agreed. The spec works for this example; it’s a bug in the compiler: https://github.com/openjdk/jdk/pull/5717
Gavin
More information about the amber-dev
mailing list