There are too many error handling conventions used in library code!

ajb at spamcop.net ajb at spamcop.net
Sun Mar 11 08:02:44 EDT 2007


G'day all.

Quoting Donald Bruce Stewart <dons at cse.unsw.edu.au>:

> This article on the 8 different error handling strategies various common
> Haskell libs use:
>
> http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors
>
> got me thinking:
>
>     we need to standardise/recommend a small set of methods for library
>     error handling.

For the record, here are the eight ways:

1. Call error
2. Return Maybe
3. Return Either
4. Return a generic Monad, a.k.a. NotJustMaybe.
5. Use MonadError and a custom error type.
6. throwDyn
7. ioError and catch
8. Monad transformers, implementing some combination of the above.

Note: NotJustMaybe is claimed to be a generalisation of 1-3; in fact
that's not quite true, since using this idiom to call Error does require
a wrapper call.  Perhaps this wrapper should be given a shorter and
snappier name than runIdentity?

One other one has been left out, and that's continuation-based error
handling.

Some general comments:

1. I've never seen some of these (8 in particular) used in any general-
purpose library.

2. If it doesn't cross an API boundary, it's none of my business what
error handling scheme you use.

3. Prolog, sadly, encourages failure-driven loops.  Java, even more sadly,
seems to encourage loops where normal termination is achieved by throwing
an exception.  Haskell, by contrast, never encourages a compromise like
that.

4. There are clearly different kinds of error/exception, and we shouldn't
expect one size to fit all.

As some examples:

    - Failure to meet a precondition includes division by zero, head of
      an empty list, array bounds checking etc.  Anything which the
      client could trivially ensure but hasn't must be due to a bug in
      the client code.  Calling "error" is appropriate.

    - True absence of a return value, such as looking up a value in a
      Data.Map which isn't there, calls for Maybe or generic Monad.
      In the absence of a short-and-snappy version of runIdentity,
      there is an argument for also providing an "error" version.
      We need a good naming convention for this.

    - Exceptions are _undesired_ conditions which would otherwise
      break the logical flow of control.  These come in two varieties:
      Some you want the client to intercept and deal with (e.g. Parsec
      parse errors) and some you want to leave it up to the client to
      decide (e.g. most I/O exceptions).

>     * what role does MonadError play here, as a generic error handler?

I think this is a perfect fit for any exception which the client MUST
deal with.  It's the Haskell equivalent of Java's checked exceptions,
which are a right royal pain when they're mandatory, but occasionally a
godsend when they're not.

>     * can we make precise recommendations about which error strategies to
> use?

No, but I think we can state some general principles.

Cheers,
Andrew Bromage


More information about the Libraries mailing list