Better exception handling

Aaron Scott-Boddendijk talden at gmail.com
Tue Mar 23 23:40:37 UTC 2021


> Much of the pain of checked exceptions is not intrinsic to the language
mechanism itself,
> but to the way checkedness is determined (an exception is checked if it
> extends Throwable but not RuntimeExcpetion or Error) and by misuse of
> checked exceptions in early libraries

Another pain-point is the lack of composability of checked-exception types
over generics (or rather than exceptions don't have special handling within
generics).

You can write...

     ThrowingFunction<T, U, X> { U apply(T t) throws X; }

But have no way to compose two functions with differing X1 and X2 without
throwing away type-information, and no way to nicely elide the 'X' when
there is no exception (or no checked exception).

I had wondered about an option 'throwing position' generic argument and an
| notation for composing the value

    ThrowingFunction<T , U, throws X> { U apply(T t) throws X; }
    ...
    ThrowingFunction<Source, Intermediary, throws FailureOne> first = ...
    ThrowingFunction<IntermediaryOne, IntermediaryTwo, _> second =  ... //
eliding the throws is an option, Specifying Void or RuntimeException is an
option.
    ThrowingFunction<IntermediaryTwo, Target, throws FailureTwo> third =
...
    ThrowingFunction<Source, Target, throws FailureOne | FailureTwo> chain
= first.andThen(second).andThen(third);

It would conceivably enable a version of APIs like 'Stream' API that could
propagate exceptions (and other useful constructs) - especially if adding a
'throwing position' argument were type compatible with callers eliding it

But this is adding to quite a few places in the language, would be hard to
use in a non-verbose manner and no doubt has some hairy edge-cases.

And that's without even thinking about how this combines with established
APIs.

Several increasingly popular languages are going in the other direction
from 'unchecked' (not using exceptions mind you), making error-checking
something you can't ignore.

Not only is the 'checked exceptions suck' opinion not universally held
within the Java community, but the lack of them in languages like C# is
even occasionally derided by users of stricter languages. Without
checked-exceptions, you're at the mercy of vendor documentation to know
which exceptions to catch - making that the compiler's job is a strength in
the language (especially if the modes of failure change with a dependency
version update).

They're not wrong about the amount of ceremony though (especially in
use-site cases where the caller knows certain exception  cases are not
relevant).

--
Aaron Scott-Boddendijk


On Wed, Mar 24, 2021 at 12:53 AM Brian Goetz <brian.goetz at oracle.com> wrote:

> People have probably been hesitant to reply because they have seen what
> happens when someone starts a discussion on checked exceptions (it's not
> pretty).  Let me just try to summarize where things are from the
> previous thousand such discussions....
>
> Joe Duffy said just about everything there is to say about error models:
>
>      http://joeduffyblog.com/2016/02/07/the-error-model/
>
> The main takeaways are:
>
>   - They are all unpleasant, but for different reasons that bother
> different people differently, and people tend to be unpleasantly
> religious about their favorite model, which makes reasoned discourse
> difficult;
>
>   - Error models are a property not only of the language but of the
> ecosystem as a whole; if different libraries have different error
> models, they can't be composed.
>
> To which I'll add:
>
>   - For an opinion like "checked exceptions suck", it is very easy to
> convince yourself that this opinion is universally held.  It is not.  It
> is just that the people who hold this opinion (and there are plenty) are
> vocal about it, and the silent majority who think it's "meh, not great,
> but good enough" are quietly getting their work done and don't bother to
> engage in the argument.
>
> Which is to say, Java has picked its model, and while we can complain
> about it (but not here, please), it is what we have, and it is not as
> bad as people would like to make it out to be. Much of the pain of
> checked exceptions is not intrinsic to the language mechanism itself,
> but to the way checkedness is determined (an exception is checked if it
> extends Throwable but not RuntimeExcpetion or Error) and by misuse of
> checked exceptions in early libraries, before we came to a better
> understanding of when to use one vs the other.  Even if the language
> offered help at the use site, the fact that InputStream::close throws a
> checked exception is still going to be a problem (what are you supposed
> to do, close it again?)
>
> To your point, yes, there are things that could be done to reduce the
> syntactic pain of checked exceptions.  But, as you point out,
> straightforward try-catch expressions don't remove most of the overhead;
> they just trim around the edges. Exceptions are better than statements,
> so this is not nothing, but for most people, it would be met by "but
> that doesn't fix my problem."  There are more aggressive things that a
> "try" expression could do, but they would require deeper intrusion into
> other parts of the language, so this is not an "easy fix" (though still
> a viable avenue for exploration.)
>
> (As an overlay that makes the problem even more difficult, the rhetoric
> over this particular topic is so toxic that it makes one less inclined
> to invest a lot of energy; it is virtually guaranteed that whatever we
> would propose would likely be met with such bile on the part of the
> haters, that I struggle to see a move that will actually make people
> happy.)
>
>
>
>
>
> On 3/21/2021 4:20 PM, d3coder wrote:
> > Try-catch expression would be really good feature, to avoid exception
> handling
> > bugs, i'm writing code like this:
> >
> > MyObject myObject;
> > try {
> >      myObject = myObjectFactory.newInstance();
> > } catch(IOException e) {
> >      throw new CustomException("Can't fetch", e);
> > }
> > myObject.doSomething();
> >
> > Sometimes i do similar code, but with automatic resource handling, e.g.
> > try(InputStream is = openStream())
> >
> > Any ideas how this could be made better? I though about try-catch
> expressions,
> > but it's still a lot of a code; I've thought about helper method like
> > getOrThrow(supplier, exception -> {}), but it's still feels like a half
> > solution
> >
> > Maybe language can offer something like ? syntax or would be try-catch
> > expressions enough?
> >
> >
>
>


More information about the amber-dev mailing list