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