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.


Reply via email to