instanceof and exceptions

Brian Goetz brian.goetz at oracle.com
Fri Oct 9 14:59:27 UTC 2020


There's a simple (though unsatisfying) answer to your student's 
question: because catch is special.  (But this answer belies an 
important point: ad-hoc syntactic "patches" like multi-catch may be 
satisfying in the short term, but they always beget a flurry of "for 
consistency" arguments, which can often not be consistently satisfied.)

Essentially, you are asking whether (a) OR patterns make sense, and (b) 
whether we can reuse the syntax A|B for OR'ed type patterns.  Let's pull 
on that string for a bit.

Suppose that `(T|U) tu` were a type pattern.  The type test is clear 
enough, but what is the type of `tu`?  There are two candidates; a union 
type and LUB.  (Union types are clearly more general, but what does 
multi-catch do?  It does LUB.  See JLS 14.20.)  I suspect your preferred 
answer is "union type", since that's a more information-preserving 
answer.  One downside here is it provides a(nother) vector for 
non-denotable weird types to escape to where users can observe them.  
(We faced a similar issue in Lambda (and LVTI): both allowed 
intersection types to escape more freely into the wild, and both had 
consequences.) It's a possibility, but I'm not sure it clears the bar 
for risk/reward.

A more general answer that doesn't involve introducing new syntactic 
forms into the language would be to dust off the proposal for binding 
variable merging:

     if (x instanceof RuntimeException e || x instanceof Error e) { X }

Our original design allowed for this but we backed off because it was 
unclear whether the return-on-complexity was justified. Here, we'd see 
that we have two patterns, each with a binding of the same name, and 
exactly one of which can produce a binding at X.  So we can give `e` 
either a LUB or union type, just as with the "shortcut" T|U, but its a 
more general solution, and doesn't tease users with a "fake" union type 
syntax.

Note that the "merging" situation has another analogue with the same 
semantics: fallthrough.  The above is like:

     switch (x) {
         case RuntimeException e:
         case Error e:
             X;
     }

If fake union types are not great, what about real union types? Well, 
it's been shown to be possible 
(https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.158.1253&rep=rep1&type=pdf), 
but its a lot; it seems like the cost-benefit isn't there either.

Overall, I'm skeptical that the cost/benefit of union type patterns is 
positive, but they are doable.





On 10/9/2020 6:11 AM, Remi Forax wrote:
> Following the course on exceptions, where i explain that a catch() is an instanceof,
> two different students ask me why catch() can use '|' in between the exception types but instanceof can not.
>
> i.e why this code works
>    try {
>      ...
>    } catch(RuntimeException | Error e) {
>      throw e;
>    } catch(Throwable t) {
>      ...
>    }
>
> but this one doesn't
>    try {
>      ...
>    } catch(Throwable t) {
>      if (t instanceof RuntimeException | Error e) {
>        throw e;
>      }
>      ...
>    }
>
> I wonder if people will want to do pattern matching on exceptions ?
>
> Rémi

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


More information about the amber-spec-experts mailing list