logo       
Google Custom Search
    AddThis Social Bookmark Button

Re: Exceptions considered harmful: msg#00077

Subject: Re: Exceptions considered harmful
On Tue, 29 Jun 2004, Bardur Arantsson wrote:

> *) Exceptions currently do not carry any useful
> __programmer-accessible__ information about where the
> exception occurred (i.e. stack contents).

Defining what the stacks' contents are is tricky in the face of tail call
optimization- the stack may have already be partially freed.  Consider
three functions, a, b, and c.  a calls b in a tail all, and b calls c in a
tail call.  Function c throws an exception.  You call a from function foo
(not a tail call, so foo stays on the stack).  Since they're tail calls, 
the stacks for a and b have already been freed by the time c throws an 
exception, so your stack makes it look like foo directly called c, which 
it didn't.  So if, for example, c was called with a bad value, a stack 
trace won't help you find who the real culprit is.

> 
> *) Few of the current StdLib exceptions carry enough
> semantic information about the exception to debug
> sensibly, e.g. the Invalid_arg exception doesn't mention
> _which_ variable had an invalid value, 

This is a good point- something extlib could improve upon.

Note that I don't consider error handling a performance critical path.  
Which means it'd be OK to do stuff like:

if (arg1 < 0) || (arg1 > n) || (arg2 < 0) || (arg2 > n) then
    (* we have an invalid arg *)
    if (arg1 < 0) then
        invalid_arg 
            (sprintf "Foo arg1 = %d, negative values not allowed!"
                     arg1)
    else if (arg1 > n)
        invalid_arg
            (sprintf "Foo arg1 = %d, value larger than n = %d!"
                     arg1 n)
    else
        ...
else
    (* args are valid... *)

For the critical path, this code is no slower than:
if (arg1 < 0) || (arg1 > n) || (arg2 < 0) || (arg2 > n) then
    invalid_arg "Foo" (* hey, who needs debugging information? *)
else
    ...

Once we detect that we're going to throw an exception, spending some extra 
time deciding which exact exception we're going to throw isn't a problem.

> *) Raiseable exceptions do not have to be declared.
> Although this may seem like B&D to some people, it does
> make it *much* easier to be disciplined and clear about
> what error information your code catches/handles/throws
> away. 

The unanimous opinion of all the Java programmers I've talked to is that, 
while this looks good on paper, it's a royal pain in the kiester in 
practice.  Ocaml's strong type checking works because it's much easier to 
work with the type system than it is to subvert it.  Type inference might 
releive some of the pain, but Ocaml's inference isn't complete enough.

In the Java world, you do see a lot of code like:

    try {
        ...
    }
    catch (Exception e) {
        /* Do nothing- I just don't feel like writting a throws clause */
   }

This is worse than the current problems.  We'd be back in the bad old days 
of programs ignoring error return values.  I'd much rather have uncaught 
exceptions than discarded exceptions.

> (Of course, one might want something similar to the
> RuntimeException in Java to avoid drowning in exception
> handling code for exceptions which are (should be) rare
> and are usually fatal and a clear sign of grave programmer
> error).

Yep.  At which point everyone inherits their exceptions from 
RuntimeException, wether they're rare or not.  

> I'm still not convinced that it's not better to simply
> explicitly return
> 
>       `Success <value>
>       `Failure <exception_type>
> 
> from all functions which can potentially fail (in a
> non-RuntimeException kind of way). Given those and a
> "die-horribly-if-failure-but-return-result-otherwise"
> function and the "ignore" built-in error handling is much
> more explicit and arguably just as simple.

This is, vaguely, what C does.  At which point error handling strategies 
fall into two broad categories:

1) ignore the error, and fail in some later spot of the code (generally by 
a segv) in a way that gives you absolutely no error recovery or debugging 
information.

2) Print an error message and exit the program.  Which is the default 
behavior of uncaught exceptions.

-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian



-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 - 
digital self defense, top technical experts, no vendor pitches, 
unmatched networking opportunities. Visit www.blackhat.com



Try Searching:
servers, voip, java, networking, microsoft ...
<Prev in Thread] Current Thread [Next in Thread>