[mercury-users] exceptions and cc_multi

Fergus Henderson fjh at cs.mu.OZ.AU
Fri Dec 1 12:52:20 AEDT 2000

On 29-Nov-2000, Paul Massey <pma at miscrit.be> wrote:
> > From: Fergus Henderson <fjh at cs.mu.OZ.AU>
> >   On 29-Nov-2000, Michael Day <mikeday at corplink.com.au> wrote:
> >   > 
> >   > Why are try and try_io both cc_multi,
> >
> >   Because the result depends not only on the value of the
> >   higher-order argument, but also on how the compiler
> >   chooses to evaluate that argument.  For example, you
> >   could call some code that could get two different
> >   exceptions depending on the order of execution,
> >   e.g. `throw(1), throw(2)'.  Or you could call code that
> >   might or might not throw an exception, depending on the
> >   order of execution e.g. `throw(1), fail'.
> I've been wondering about this and whether the semantic
> niceties are really that relevant in this case.
> In the server we've been developing some of the more
> annoying problems are a result of an exception being thrown
> in a part of the code considered as being (exception) safe.
> The information regarding exceptions seems to be at
> completely the wrong place. For example, Map__det_update/3
> is marked as being 'det' when it could potentially throw an
> exception and break my code/server,

map__det_update should never throw an exception, because you should
never call it with arguments that would cause it to throw an
exception.  If you ever call map__det_update with arguments that cause
it to throw an exception, that is a bug in your code.
In general, you should never write programs that rely on catching
`software_error' exceptions.  Instead, you should make sure that the
conditions that would cause such exceptions to be thrown never occur.

Of course, everyone makes mistakes, and it is desirable for programs
to be robust enough that they can recover from such bugs and
continue operating anyway (after having logged the problem).
That's why error/1 throws an exception and why we let you catch such
exceptions.  However, that should only be used as a fall-back; you
should never write code that deliberately relies on this.

Note that in general *any* recursive predicate could have a bug in it
that causes it to go into an infinite loop, and the runtime system
could detect that and throw an exception.  Similarly, any predicate
call might run out of stack space (or some other resource), and the
runtime system could detect that and throw an exception.  Our current
implementation doesn't do that, but this would certainly be allowed by
the Mercury language specification, and would be helpful, since it
would let you write more robust programs that recover from those errors.

So as far as exceptions are concerned there is really nothing more
dangerous about predicates that can call error/1 than there is about
predicates which might loop or predicates which use stack space.  It
would be pointless to annotate `map__det_update' with something saying
that it might throw an exception, since we'd then have to put the same
annotation on *every* procedure.

For this reason, adding exception specification declarations
for things like map__det_update would not be very useful.

Note that in this respect the exceptions thrown by map__det_update are
qualitatively different than the ones thrown by e.g. io__write_string.
It *is* OK to write programs that sometimes throw `io_error' exceptions.
So, you might argue that we should extend Mercury to allow exception
specification declarations, and use them for things like `io__write_string'.

However, there are technical difficulties with exception specifications
for higher-order predicates and for type class methods.
Futhermore, using exception specifications like that would negate one
of the key advantages of having exceptions in the first place.
The nice thing about exceptions is that they let you decouple
the middle-level code from all considerations of error handling.
Only the bottom-level code which throws the exception and the
top-level code which catches the exception need to know about it.
This is nice, because it makes code reuser easier.
With type classes, I can develop a whole infrastucture of
middle-level code, and you can come along and call my infrastructure,
plug in your own bottom-level code in a type class instance

Using statically enforced or even dynamically enforced exception
specifications would break this style of code, because in this style
of code the middle-level code does not know which exceptions the
low-level code throws.  Enforced exception specifications would thus
make code reuse a lot more difficult.

Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe

More information about the users mailing list