[m-dev.] checked exceptions.

Paul Bone paul at bone.id.au
Wed Feb 13 14:01:44 AEDT 2013


On Wed, Feb 13, 2013 at 10:19:50AM +0800, Michael Richter wrote:
> Let me put in a negative vote here.  I think checked exceptions are evil.
> They were one of these things that *sounded* really good in theory but have
> turned out in practice to make things worse—by far—than had they never
> existed.
> 

You and the others apposed to this idea have given some very clear reasons
why not.  Meanwhile there are few reasons _for_ such a change - including my
own.  Therefore I will not implement checked exceptions in this way.



> When I have checked exceptions I have to check the exception signature of *each
> and every* predicate or function I call and do one of the following:
> 
>    1. Add the exception to my signature.

The only rebuttal I have for this point is that it provides documentation.
This is not a convincing point as this is the same documentation that we try
to provide by using the type system properly.  As Micheal D said: why do you
need checked exceptions when you have DU types?  Mostly he's correct, and I
think that the remaining cases are rare and not worth while.

>    2. Catch-and-convert the exception.

It can be argued that this helps with information hiding.  If I'm using a
3rd party library I may not care why that library failed, just that it did
fail.  The same expressiveness can also be made with DU types so this is not
really a point for or against checked exceptions.

> Now let's look at composition.  Checked exceptions completely and utterly
> break composition.  The *whole point*, for example, of higher-order code is
> to decouple execution patterns from the specifics of execution.  Let's
> consider a simple situation of mapping a function/predicate against a
> list.  What exceptions should be declared on that mapping function?  Well,
> I might do division in the passed-in function, so I'll need to catch divide
> by zero errors.  So now my list mapping code has to declare divide by zero
> as a possible exception, even though there's *nothing* in its actual code
> that can do this.  Now what happens if I'm mapping a function provided by
> some third-party that declares some_random_exception in its interface?  Now
> my map has to somehow know about this third-party exception in advance and
> declare it in its interface.  This is both clearly impossible and
> ridiculous.  So what do I have to do instead?  Oh, right.  I'm back at
> catch-and-convert and I've just, once again, missed the entire point of how
> exceptions are supposed to simplify and ease error handling.  Somewhere in
> this process I've just made composition, arguably the entire *point* of a
> good modern, declarative language, more difficult for no good reason.
> (Because most exceptions just get logged or used to generate an error
> message and a clean shutdown anyway.)

The higher order problems can be avoided by making this information
polymorphic.

> Now all this doesn't mean I'm opposed to the notion of having some way to
> check exception throwing and handling.  I just don't think it should be
> part of the language.  I'm going to invoke something better (IMO): external
> tooling.
> 
> Consider Erlang.  Erlang is a dynamically typed language with an
> *external*static type checker (using an unusual kind of typing called
> "success
> typing", however).  I think a static analysis *tool* would be a better fit
> for checking exceptions.  This tool would read the source code and simply
> make reports on exception handling, spotting chains of code where
> exceptions bubble up to the main predicate and out without being handled.
> This would give you the purported benefits of checked exceptions without
> the liabilities of cluttering up a code base with endless ceremony (which
> lazy programmers *will* just turn into empty catch clauses anyway!).

I agree.  In the long term an external tool would be great for things like
this.  In fact a suite of such tools would be useful (ie to create pettier
documentation).

However, there is a significant engineering task in modifying the compiler
so that it can support more powerful external tools, it's quite monolithic.
While it is a good idea to keep tools separate so that their implementations
can be kept simple and aren't tightly coupled, it's not strictly necessary.

The thing that external tools get right is that they do not require any
annotations in the source program.  Ocamlexp is one such program for
exception analysis.  (It seems that the Ocaml project is a example of some
good engineering.)  This avoids the problems you and others have identified
with checked exceptions, while still giving us a way to identify uncaught
exceptions.

Therefore, the most feasible solution for Mercury seems to be some compiler
support for gathering information along with an external tool that processes
the information and presents a report to the user.  Does anyone see a
problem with putting more specific exception information into .int (or
similar) files during compilation and creating a small tool to process this
information?

Thanks for your comments everyone.  The feedback is really helpful.


-- 
Paul Bone
http://www.bone.id.au



More information about the developers mailing list