<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Brian Goetz" <brian.goetz@oracle.com><br><b>To: </b>"Remi Forax" <forax@univ-mlv.fr><br><b>Cc: </b>"amber-spec-experts" <amber-spec-experts@openjdk.java.net><br><b>Sent: </b>Wednesday, December 13, 2023 12:04:09 AM<br><b>Subject: </b>Re: Effect cases in switch<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<blockquote cite="mid:327307323.80228032.1702420883408.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;">
<br>
Exception cases can be used in all forms of `switch`:
expression and statement<br>
switches, switches that use traditional (colon) or
single-consequence (arrow)<br>
case labels. Exception cases can have guards like any other
pattern case. </blockquote>
<div><br>
</div>
<div>I think I would prefer "case throws" to be spell "catch"
even if we have to have a discussion about catch(Throwable
t) vs catch Throwable t.<br>
</div>
</div>
</div>
</blockquote>
<br>
Ah, you've stepped in the trap. You know the rule: if you make a
syntax comment, you've implicitly signed up for all the semantics.
Glad to know you're on board :)<br>
<br>
We knew that someone (everyone?) would ask about this, because its
kind of the obvious choice. But having thought about it for quite a
while, I'm firmly convinced that this is in the "obvious but wrong"
department. PLEASE, let's not have a back-and-forth on this,
because I don't want a substantive discussion to be derailed by a
syntax triviality (we can return to this topic after the
substantitive discussions have played out), but I will summarize
some of the reasons why this is not what we want, because I think
they are relevant to the goals of the feature:<br>
<br>
- The semantics would be extremely confusing, because a `case
throws` matches only exceptions thrown _in evaluating the selector_,
just like other cases match the result of a successful evaluation of
the selector. But if we expressed this as `switch ... catch`, users
would forever be assuming, incorrectly, that they mean to be
catching all errors from the switch block, including both those from
the selector and those from the body. That is *not* what this
construct is about. <br>
<br>
- The *whole point* of this feature is allowing evaluation failures
to be handled consistently and uniformly with successful
evaluation. Having a different syntax for handling failures does
not help and does not highlight the uniformity. Again, that is not
what this constructs is about. <br>
<br>
The keyword `catch` is familiar but that is a very short-lived
benefit. The purpose of the feature is to allow uniform handling of
results and effects; the syntax should reflect that.</blockquote><div><br></div><div>I do not like case throws. I see why you like it, you want to do a case but not on the value of the expression but on the exception raised from the exception.<br data-mce-bogus="1"></div><div>It has also the advantage of being clears that a "case throw" can not catch exception like MatchingException that are. throws while executing a matching.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>But syntactically, if a "case throws" throws an exception, we have throws and throw on the same line, which is just awful to read<br><div> case throws Exception e -> throw new AppException(e);</div></div><div><br></div><div>Also it does not convey the right semantics, a "case throws" is not a "case", you can not mix it with the other cases and the merging of exceptions does not works like the merging of values,<br></div><div>Some like case throws RuntimeException | Error e -> ... should be valid.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>For now, i think that __rescue is a better keyword, because unlike case and catch it does not have any existing semantics attached.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<br>
<br>
<blockquote cite="mid:327307323.80228032.1702420883408.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>
<div><br>
</div>
<blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<br>
Exception cases have the obvious dominance order with other
exception cases (the<br>
same one used to validate order of `catch` clauses in
`try-catch`), and do not<br>
participate in dominance ordering with non-exceptional
cases. It is a<br>
compile-time error if an exception case specifies an
exception type that cannot<br>
be thrown by the selector expression, or a type that does
not extend<br>
`Throwable`. For clarity, exception cases should probably
come after all other<br>
non-exceptional cases. <br>
<br>
When evaluating a `switch` statement or expression, the
selector expression is<br>
evaluated. If evaluation of the selector expression throws
an exception, and<br>
one of the exception cases in the `switch` matches the
exception, then control<br>
is transferred to the first exception case matching the
exception. If no<br>
exception case matches the exception, then the switch
completes abruptly with<br>
that same exception. </blockquote>
<div><br>
</div>
<div>I don't want to be the guy implementing this :)</div>
</div>
</div>
</blockquote>
<br>
Good news, Jan has volunteered to be that guy :)</blockquote><div><br></div><div>Are you sure you do not want a VM guy too ?<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
<br>
<blockquote cite="mid:327307323.80228032.1702420883408.JavaMail.zimbra@univ-eiffel.fr">
<div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000">
<div>
<div>I understand the appeal of such construct, it's a way to
switch (eheh) from a world with exceptions to a more
functional world where errors are values.<br>
</div>
<br>
</div>
</div>
</blockquote>
<br>
And even more so, to allow existing effectful APIs (like
Future::get) to be consumed as uniformly as they are implemented. </blockquote><div><br></div><div>Future::get as several issues, for me, the main one is that Callable/Future does not tracks the exception type so the cause of an ExecutionException is a Throwable so you are required to do a pattern-matching on the cause to repropagate at least the Error correctly.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>That said, exceptions are a good candidates for a deconstructor, i'm sure people will want to write<br data-mce-bogus="1"></div><div> switch (future.get()) {<br data-mce-bogus="1"></div><div> ...<br data-mce-bogus="1"></div><div> __rescue ExecutionException(Error error) -> throw error;<br data-mce-bogus="1"></div><div> }<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>---<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>Also, I believe we are in trouble if the expression of the switch is typed as AutoCloseable, <br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div> var paths = switch(Files.list(path)) {<br data-mce-bogus="1"></div><div> Stream<Path> stream -> yield stream.toList();<br data-mce-bogus="1"></div><div> __rescue IOException _ -> List.of();<br data-mce-bogus="1"></div><div> };<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>because users will want the switch to call close() on an AutoCloseable but it's not a backward compatible change.<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div><div>regards,<br data-mce-bogus="1"></div><div>RĂ©mi<br data-mce-bogus="1"></div><div><br data-mce-bogus="1"></div></div></div></body></html>