Effect cases in switch

Brian Goetz brian.goetz at oracle.com
Tue Dec 19 00:34:57 UTC 2023


Turning to Remi's other comments: these are basically about interaction 
of this feature with the two throw-related features that came in in Java 
7 -- multi-catch and try-with-resources.

In Java 7 we got multi-catch; you can say

    catch (E1|E2 e) { ... }

There are several problems with multi-catch; most notably, the typing of 
the catch formal (it is a LUB, rather than an intersection type.)  This 
in turn causes another problem -- a multi-catch that does `throw e` 
should fail (since the LUB of two exceptions may well not be permitted 
by the throws clause of the enclosing method, even if both alternatives 
are.)  So another hack was added when adding multi-catch; that if the 
operand of `throw` is an effectively-final catch formal, it is allowed.

Separately, some day we may want to make the operand of a catch clause a 
pattern, and not just a declaration of a local variable whose type 
extends Throwable.  This would be useful when we add deconstructors that 
support exception chaining:

     catch (RuntimeException(IOException e)): ...

But it is far from clear that we want (a) to support union type patterns 
or (b) if we did, we want the syntax to be `A|B e`.  We will surely have 
to navigate this when we get to the point where we consider making 
`catch` a pattern-aware context.  Presumably, once we address this for 
`catch`, the story for `case throws` will follow.  But it is not require 
that we mirror the behavior of `catch` in `case throws`, any more than 
we were forced to do constant patterns when we did patterns in switch 
(even though you can say `case 0`.)  So I think we do not have to solve 
this now, maybe we will address it later in conjunction with catch 
clauses, and maybe we never will, and all of those outcomes are OK.


Turning to try-with-resources; there's an alternate form of the `try` 
header which can declare one or more resources:

     try (R r = e)

When this is present, one or more implicit finally clauses will ensure 
that the close() method is called.

Does this mean than an exceptions-aware switch has to do the same?  I 
think the answer is a pretty clear "no".  In a switch:

     switch (f(n)) { ... }

where evaluation of f(n) might throw, we _already_ expect f to have 
cleaned up any resources it opened, before returning.  There is no need 
for switch to do more.  The reason this case is different is that the 
TWR header is opening a resource that the entirety of the try block 
needs to be able to operate on; in the case of a single-expression 
selector, it's a different story.

So I think the answer to the first is "maybe, someday" and the second is 
"nope".





-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20231218/cf6c106c/attachment-0001.htm>


More information about the amber-spec-experts mailing list