[External] : Re: Proposal: Operator to "demote" checked exceptions

Brian Goetz brian.goetz at oracle.com
Wed Mar 16 15:17:01 UTC 2022


Yes, the notion of "declarative checked exception wrapping" has been 
bouncing around the ecosystem for a long time (I think I even wrote a 
mail/RFE not unlike yours ~25 years ago about it, when I first arrived 
in the Java ecosystem.)  As directions for reducing the pain of checked 
exceptions go, I agree it is a promising one.

To answer the syntax question in your mail, what you suggest would 
introduce a painful asymmetry between

     catch (E1(E2))

and

     throws E1(E2)

because the nesting notation would mean two different things in the two 
places; in the first, describing only what is caught ("an E2 wrapped in 
an E1"), but in the latter, it is trying to say "if I throw an E2, catch 
it, and rewrap it in an E1, and throw that".  I think it is too much of 
a stretch to try to reuse the same syntax for two different things.

So, my summary is that this is an understood and plausible direction, 
and something we might consider at some point, but not a feature that we 
are currently pursuing.  (Yes, we understand that checked exceptions can 
be painful.)  So, please let's not try to design the feature here -- and 
certainly let's not try to design the syntax here.



On 3/16/2022 5:12 AM, negora wrote:
> Hi Brian. Thank you for your answer and apologizes for the delay.
>
> I must admit that, in a first stage of my proposal, my idea was about
> adding some syntactic sugar to wrap/unwrap exceptions easily, without
> the need of try-catch blocks. But that led me to the idea of removing
> the need of wrapping altogether and, hence, propose the feature of
> switchable checked exceptions.
>
> My initial proposal looked like this:
>
> ```
> public Student parseStudent (String line)
>     throws StudentException
>       wraps IOException, ParseException {
>   // Code.
> }
> ```
>
> Instead of this:
>
> ```
> public Student parseStudent (String line) {
>   try {
>     // Code.
>   } catch (IOException | ParseException ex) {
>     throw new StudentException (ex);
>   }
> }
> ```
>
> Obviously, the wrapper exception should provide at least
> one constructor with a single parameter of type `Throwable`.
> And the signature of the method would not include
> the `wraps` clause.
>
> Maybe it's just me, but try-catch blocks introduce visual
> complexity that distracts me while reading the body of a method.
> It could be alleviated **a lot** with this.
>
> From my experience, many try-catch blocks are just
> to wrap checked exceptions between abstraction layers,
> so this would be very helpful in many parts of our code bases.
> In practice, the use of try-catch blocks would be reduced
> to those situations in which we need to do something
> different from just wrapping an exception.
>
> In contrast to the proposal of switchable exceptions, this
> syntax couldn't be directly applied to lambdas. But at least
> one could extract the code to a new method and keep it cleaner
> that with a try-catch.
>
> > One context that could become pattern-aware is catch. And
> > deconstruction patterns compose, so we could give exceptions
> > deconstruction patterns to match their wrapping constructors, so that
> > you could say
> >
> >      catch (RuntimeException(SqlException se)) { … }
> >
> > which reduces the syntactic overhead of unwrapping to basically
> > zero.
>
> That sounds interesting. But, Could the opposite concept be carried
> to the `throws` clause? I mean, a construction pattern
> instead of a deconstruction one. Something similar to
> my first example, but without the need of a new keyword:
>
> ```
> public Student parseStudent (String line)
>     throws StudentException (IOException | ParseException) {
>   // Code.
> }
> ```
>
> I really prefer the use of the `wraps` keyword, but I understand
> that introducing a new keyword has lots of side-effects.
>
>
>
> On 07/03/2022 21:38, Brian Goetz wrote:
>> Not going to engage on the “should we give people the opportunity to 
>> turn off checked exceptions”, but I will make a few comments on how 
>> we might reduce the accidental cost of wrapping and unwrapping 
>> exceptions.
>>
>>> 3. If you want to rethrow the original exceptions, you're forced to 
>>> catch the wrapper first, and then analyse and downcast the wrapped 
>>> exceptions.
>>
>> We’re in the process of adding pattern matching to the language, in 
>> stages.  Currently patterns are restricted to type patterns, and 
>> pattern-aware contexts are restricted to instanceof and switch, but 
>> both categories will expand over time.
>>
>> One context that could become pattern-aware is catch.  And 
>> deconstruction patterns compose, so we could give exceptions 
>> deconstruction patterns to match their wrapping constructors, so that 
>> you could say
>>
>>      catch (RuntimeException(SqlException se)) { … }
>>
>> which reduces the syntactic overhead of unwrapping to basically 
>> zero.  I’m much more compelled by directions like this, which embrace 
>> the tools we have, but reduce their accidental impact. (Obviously 
>> there’s work to do to make everything about wrapping this smooth.)


More information about the amber-dev mailing list