multi-catch vs. multiple type patterns in a single case label

Brian Goetz brian.goetz at
Fri Apr 8 21:25:42 UTC 2022

There's really three questions fused together here; one about union 
types, one about the feasibility of pattern fusion, all wrapped up in 
one about syntax.

Multi-catch was added to Java in Java 7, as part of "Project Coin"; the 
mission of Coin was highly constrained.  When extrapolating from the 
syntax of multi-catch to an imagined syntax of OR patterns, there is a 
subtle difference between:

     case (IOException | TimeoutException) e:     // parens added for effect

(Before continuing, what is the type of e?)


     case (IOExcetion e) | (TimeoutException e):  // parens added for effect

which is more of an OR of patterns.

Multi-catch did not add general purpose union types to the language; it 
focused them on one little corner.  (We can argue over whether this was 
a clever pragmatic compromise, or whether we merely created a lot of 
incremental language complexity for minor gain.)  It is possible it 
might make sense to add it in another corner too, but we're wary of such 
moves, because such types invariably escape into inference and produce 
weird, non-denotable types elsewhere.  (See the travails over how to 
sanitize capture types with `var`.)  So just copying what multi-catch 
does is not an obvious slam-dunk.

OR patterns are a more powerful mechanism, and one we'd like to 
consider, but they are complicated too.  In the second example, `e` has 
*two* declaration sites, and we still probably end up inferring a union 
type for it, or maybe we infer the least-upper-bound (which is often 
Object).  So this is also not an obvious slam dunk either.

So the short answer is that just because there is a way to express 
something somewhere, doesn't mean that carries over to other similar 
things elsewhere.  Even if the syntax would be obvious.

On 4/8/2022 10:03 AM, Tobias Gierke wrote:
> Hello,
> Having read through JEP-420, I wonder why
>     try {
>         .... do stuff ....
>     } catch( IOException | IllegalStateException e) {
>         System.out.println("Something went wrong: "+e);
>     }
> is valid but
>     Exception x = ....
>     switch(x) {
>          case IOException | TimeoutException e -> 
> System.out.println("Something went wrong: "+e);
>     }
> is not. I get that something like
>     Exception x = ....
>     switch(x) {
>          case IOException a, IllegalStateException b ->  .....
>     }
> would leave one of the variables undefined but why can't I bind 
> multiple type patterns to the same variable, have the compiler infer a 
> common super-type and use that to check the switch branch ?
> Regards,
> Tobias

More information about the discuss mailing list