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