Next up for patterns: type patterns in switch

Alex Buckley alex.buckley at oracle.com
Thu Aug 13 23:35:10 UTC 2020


On 7/23/2020 11:52 AM, Brian Goetz wrote:
> On 7/23/2020 2:38 PM, Remi Forax wrote:
>> On guards, they do not work well with exhaustiveness. Still not sure 
>> they are useful.
> 
> It works fine, it's just more work for the user to get right.
> 
> We induce a domination ordering on patterns.  If `T <: U`, then `T t` < 
> `U u` (`T t` is less specific than `U u`.)  Similarly, for all guard 
> conditions g, `P & g` < `P`.  What this says is that if you want 
> exhaustiveness, you need an unguarded pattern somewhere, either:
> 
>      case A:
>      case B & g:
>      case B:              // catches B & !g
>      case C:
> 
> or
> 
>      case A:
>      case B & g:
>      case C:
>      case Object:    // catches B & !g
> 
> I understand your diffidence about guards, but I'm not sure we can do 
> nothing.  The main reason that some sort of guards feel like a forced 
> move (could be an imperative guard, like `continue`, but I don't think 
> anyone would be happy with that) is that the fall-off-the-cliff behavior 
> is so bad.  If you have a 26-arm switch, and you want the equivalent of 
> the second of the above cases -- B-but-not-g gets shunted into the 
> bottom clause -- you may very well have to refactor away from switch, or 
> at least mangle your switch badly, which would be pretty bad.

Is the following what you mean by "mangle your switch badly" ?

switch (o) {
   case A: ...
   case B: do some B-ish stuff ... also, if (g) {...}
   case C: ...
   ...
   case Z: ...
   case Object: if (o instanceof B && !g) { do the B-ish non-g thing }
}


Is a guard (a) part of the `case` construct, or (b) part of the pattern 
operand for a `case` construct? The original mail introduced "guard 
expression" as "a boolean expression that conditions whether the case 
matches", which sounds like (a). However, the purpose of a `case` 
construct is to enumerate one or more possible values of the selector 
expression, and if a `case` construct has a post-condition `& g()` then 
it's not just enumerating, and it isn't a `case` construct anymore. I 
mean, we don't want to see guards in the `case` constructs of legacy 
switches, right? (`switch (i) { case 100 & g():`)  So, is the answer (b) ?

Alex


More information about the amber-spec-experts mailing list