Exceptions vs. Errors (Re: Readline read_history and write_history addition)

Yitzchak Gale gale at sefer.org
Wed Jan 23 05:39:52 EST 2008

Henning Thielemann wrote:
> http://www.haskell.org/haskellwiki/Exception
> http://www.haskell.org/haskellwiki/Error

The exact usage of the terms "error" and "exception" varies
between programming languages. Your descriptions on
the wiki follow Java usage, where Error and Exception
are separate subclasses of Throwable. In Python, "exception"
means the program flow construct, and "error" means a
condition in which an exception is raised due to something
going "wrong", so StandardError is a subclass of Exception.
There are other conventions.

In Haskell, the usage is, let's just say, unusual. :)
Perhaps some technolinguist will have a good time
studying it some day.

I wrote:
>> If we start throwing IO exceptions for common and minor
>> occurrences like no readline history available, libraries like
>> this become impossible to write in Haskell. And code
>> that has already been written becomes unusable.

> ...situations that cannot be avoided by the programmer
> but must be handled. An approved method to handle these
> cases are 'try' constructs.

Approved? The question is: when is it appropriate to
use this technique in Haskell? Every function that can
return more than one possible value has "situations
that must be handled", but usually we will not throw

> Now if 'bracket' does not work for general
> MonadIO then it should be generalized.

'bracket', 'try', and 'catch' do need to be generalized.
Realistically, that will not happen for a long time, if ever.
The reality is that Haskell's IO exception facilities have some
rough edges. They work great for asynchronous errors,
which is what they were designed for.

In general, whether or not IO exceptions are appropriate
in Haskell is heavily dependent upon programming style.
The only situation in which they are certainly called for is
an asynchronous error. Perhaps also a non-error that
satisfies all of the following conditions:

E1) The function is strongly in the IO monad.
E2) The condition is rare.
E3) Sometimes the correct action would be to exit the program
    with an error message.

In any other case, throwing an IO exception is an
abuse that might ruin someone's program. If an
IO exception is appropriate for the style of a particular
program, it is easy for that program to provide one.

When writing Haskell bindings for a library written in
an imperative language, there is always a tension
between providing a more idiomatic Haskell interface
and faithfully reproducing the calling semantics of
the library. When a C function returns an int to indicate
various possible outcomes, that doesn't necessarily
mean that it must throw an IO exception in Haskell,
even if the author called the int an "error code".

E2 and E3 do not hold for in the case of readline
history - if were to throw an IO exception in the case
of empty history, it would be obligatory for every program
using it to wrap the function in a try. There is no
way to express that in Haskell; you would have to write
that requirement in a comment. That itself is evidence that
the semantics of this language construct have been abused.
(As contrasted with Java, for example, where ignoring the
possible exception would cause the program to be rejected.)


More information about the Libraries mailing list