[ 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?

Reply via email to