Pattern Matching for switch (Second Preview)

Brian Goetz brian.goetz at oracle.com
Thu Sep 30 22:25:26 UTC 2021


[ moving to a-s-e ]

I get the concern that a type pattern is no longer "just a variable 
declaration"; that was a nice part of the "patterns aren't really so 
hard to understand" story.  But I think the usability is likely to be 
not very good.  Take this example:

     sealed interface Node<T> { }
     record AddNode<T>(Node<T> left, Node<T> right) extends Node<T> { }
     ...

     Node<int> ni = ...
     switch (ni) {
         case AddNode(Node left, Node right) -> ...

There's no instantiation of Node possible here *other than* Node<int>.  
Which means we are forcing users to either redundantly type out the 
instantiation (which can get big), or use casts inside the body when 
they pull things out of left and right.  (And patterns were supposed to 
make casts go away.) There's almost no case where someone wants a raw 
type here.

We faced this in method references; when referring to Foo::m, we use the 
target type to infer the right parameterization of m. Raw types are a 
migration compatibility thing, but there was no migration compatibility 
concern with method references, nor is there with patterns, since these 
are new linguistic forms.

What's different here is that we have more type information -- the type 
of the switch target.  So we can refine the type pattern with additional 
information from the target.  And I can't conceive of a case where the 
user wouldn't thank us for this.



On 9/30/2021 8:25 AM, Gavin Bierman wrote:
>
>> 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?

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210930/8fe12e25/attachment.htm>


More information about the amber-spec-experts mailing list