Next up for patterns: type patterns in switch

Brian Goetz brian.goetz at oracle.com
Tue Aug 11 22:26:42 UTC 2020


> On the other hand, I think Remi’s point about totality being an 
> implicit and non-local property that is easily undermined by code 
> changes in another compilation unit is worrisome.

... which in turn derives from something else worrisome (a problem we 
bought last year): that it is not clear from looking at a switch whether 
it is exhaustive or not.  Expression switches must exhaustive, but 
statement switches need not be.  Here, we are saying that exhaustive 
switch statements are a useful new thing (which they are) and get 
rewarded with new behaviors (some may not find it a reward), but you 
have to look too closely to determine whether the switch is total.  If 
it is, the last clause is total too (well, unless it is an enum switch 
that names all the constants, or a switch over a sealed type that names 
all the sub-types but without a catch-all.)

So I claim that, if there is a problem, it is that it should be more 
obvious that a switch is exhaustive on its target.

> Putting this all together, I reach two conclusions:
>
> (1) We can live with the current definition of instanceof, provided we 
> make it clear that instanceof is not purely equivalent to pattern 
> matching, and that instanceof and pattern matching can be simply 
> defined in terms of each other.

I think we can do slightly better than this.  I argue that

     x instanceof null

is silly because we can just say

     x == null

instead (which is more direct), and similarly

     x instanceof var y
     x instance of Object o

are silly because we can just say

     var y = x

instead (again more direct).  So let's just ban the nullable patterns in 
instanceof, and no one will ever notice.

> (2) We have a real disagreement about switch, but I think the fault 
> lies in the design of switch rather than with pattern matching, and 
> the fault is this:
>
> Sometimes when we write
>
> switch (v) {
> case Type1 x: A
> case Type2 y: B
> case Type3 z: C
> }
>
> we mean for Type1 and Type 2 and Type3 to be three disparate and 
> co-equal things—in which case it seems absurd for any of them to match 
> null; but other times we mean for Type3 to be a catchall, in which 
> case we do want it to match null if nothing before it has.

Agreed.  The fundamental concern that Remi (and Stephen, over on a-dev) 
have raised is that we can't tell which it is, and that is disturbing.  
(I still think it won't matter in reality, but I understand the 
concern.)  The same ambiguity happens with deconstruction patterns:

     case Type3(var x, var y, var z) t3: ...

which we can think of as "enhanced" type patterns.

(encouraging that our mails crossed with mostly the same observation and 
possible fix.)

> I believe some previous discussion has focused on ways to modify the 
> _pattern_ to indicated either an expectation of totality or a specific 
> way of handling null.  But at this point I think augmenting patterns 
> is overkill; what we need (and all we need) is a modification to the 
> syntax of switch to indicate an expectation of totality.  I have a 
> modest suggestion:
>
> switch (v) {
> case Type1 x: A
> case Type2 y: B
> case Type3 z: C    // Type3 is not expected to be a catchall
> }
>
> switch (v) {
> case Type1 x: A
> case Type2 y: B
> default case Type3 z: C    // Type3 is expected to be a catchall; it 
> is a static error if Type3 is not total on v,
> // and Type3 will match null (unlike Type1 and Type2)
> }

And we already had another reason to want something like this: 
expression switches are exhaustive, statement switches are not, and we'd 
like to be able to engage the compiler to do exhaustiveness checking for 
statement switches even in the absence of patterns.

> Now, I will admit that this syntax is a wee bit delicate, because 
> adding a colon might apparently change the meaning:
>
> switch (v) {
> case Type1 x: A
> case Type2 y: B
> default: case Type3 z: C
> }

Or `final case` or `finally <pattern>` or `default-case` or ...

I am iffy about `default` because of its historical association, but I 
will have to re-think it in light of this idea before I have an opinion.

> but I believe that in situations that matter, the compiler can and 
> will reject this last example on other grounds (please correct me if I 
> am mistaken

yes, the compiler can catch this.

The other degree of freedom on this mini-feature is whether `default` is 
a hint, or whether it would be an error to not say `default` on a total 
pattern.  I think it might be seen as a burden if it were required, but 
Remi might think it not strong enough if its just a hint.


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


More information about the amber-spec-experts mailing list