
Why Exceptions Suck - edw519
http://www.ckwop.me.uk/Why-Exceptions-Suck.html
======
mojuba
_Exceptions are a super GOTO. Rather than allowing you to jump anywhere in the
position of the procedure, they allow you to teleport up the call stack to any
number of handlers._

Wrong. Exceptions, unlike GOTOs, can't jump straight into a loop or any
construct that has a local state. In fact, exceptions never break local
states, and that's their beauty.

The best proof that exceptions don't break anything is that you can always
represent a throw/catch cycle with IF's, RETURN's, possibly also subroutines,
but there will be no GOTOs. You will have equivalent functionality, except the
code will be a bit bloated and less readable.

~~~
jcromartie
What about the case of "finally" blocks executing after return?

~~~
mojuba
You mean, how can that be replaced with ordinary operators? If you have
multiple return's, move your 'finally' block to a separate function and call
it before every 'return'.

~~~
AndyKelley
I have never been able to use the finally block. I have yet to see an example
where you would want to use it.

~~~
mojuba
In languages with implicit construction/destruction facility, like C++, you'd
probably live happily without the finally block. There are however situations
in C++ when you want to create a class with ctor/dtor only to make sure some
block is executed when going out of scope, no matter how. That dtor would be
your finally block.

~~~
gaius
Indeed - once I discovered __del__ in Python, I immediately started to do it
that way instead.

------
olavk
He argues that developers are generally too stupid and lazy to use exceptions
correctly (which may be true), but if they instead are forced to use manual
error code checking (which achieves the same, but requires typing lots of
tedious and fragile boilerplate code) - they would do it diligently and
correctly.

I'm not sure I buy that.

~~~
demallien
I didn't really think that that was his core argument. From my reading, he was
saying this:

1) Exceptions that arise from a bug should just assert 2) Exceptions that
arise from an expected 'exceptional' are actually part of the true logic of
the program, and shouldn't be shunted off into a catch/rescue block, because
that increases the temptation to consider these as being some how subordinate
to the 'happy case'. 3) The fact that exceptions are easy to propagate up the
stack means that they can break encapsulation, and it becomes easy for lazy
programmers to not treat special cases correctly.

Of course, I may be completely wrong about that, but I just thought I'd share
what I had understood, as it's apparently different to your interpretation.

~~~
olavk
I agree with you interpretation, I just don't agree with the logic that if
developers are too lazy to handle exceptions, they will do the alternative
(checking and handling return values) correctly, since it is just as easy to
ignore an error code return value than it is to ignore an exceptions.

And if we agree that lazy developers might not handle every error, the
"default case" with ignoring exception (the exception propagates to the top
and kills the program) is much preferable than the default case without: the
program state becomes corrupted, but the program keeps running.

Another point: Exceptions are not for cases which can be handled as part of
the normal flow. Rather they are for exceptional cases which requires you to
break out of the current context and handle the error on a higher level. So if
you use exceptions correctly they don't break encapsulation, rather they help
encapsulation since you can handle errors at the appropriate level.

------
mynameishere
_For a start, unless you're Google, attracting talent is hard._

Why do people keep parroting this?

 _It's much harder to use a return code badly_

Return codes are almost always ignored. In straight C, errors are a real pain.
They just are. In working code, the evils of exceptions don't come up, because
you don't get exceptions for the most part. As a practical matter, they're
just debugging tools, and not control handlers.

~~~
kylec
_In straight C, errors are a real pain. They just are. In working code, the
evils of exceptions don't come up, because you don't get exceptions for the
most part. As a practical matter, they're just debugging tools, and not
control handlers._

This is 100% true. I was once trying to do something with POSIX semaphores on
OSX and while the code compiled without so much as a peep and ran, the
semaphore didn't seem to be working. Only after meticulously examining my
semaphore calls and printing out the error codes was I able to discover that
sem_init doesn't work on OSX. (At least this was my experience). This would
have saved me hours of debugging time if the compiler spat out a warning
instead.

~~~
ajross
Well, sorta. Honestly, the problem here was that your platform sucked. If
sem_init() "doesn't work" on OS X (is that really true?), there's no guarantee
that the putative exception-enabled version would be properly throwing an
exception either. Exceptions can be really useful, but they won't fix broken
libraries for you.

And it's also true that the POSIX synchronization primitives are a good
example of how _not_ to implement error handling in a C API. Too many things
that are fundamentally usage errors (and should be caught at compile time) are
flagged at runtime, leading to the silent failure issue you saw.

~~~
kylec
You're right, my post had less to do with exceptions and more to do with
venting my frustration at the less-than-helpful C error handling system. It's
not good when the API makes you think you're losing your mind.

------
gizmo
When reading C code either all return codes are checked or not. Either way you
know whether errors are dealt with. If you don't check a pointer before
dereferencing it - the code is wrong. It's that simple. Correct code looks
correct, crappy or unfinished code looks crappy or unfinished. This is a good
thing.

When you read Ruby code you have no idea if the programmer thought about
exceptions at all. In order to figure out what exceptions should be possibly
handled you have to take the union of all the exceptions that can be thrown by
all the functions you call, and _then_ check if they are all handled
correctly. Unfortunately, it's impossible to determine which exceptions can be
thrown by a function, because any function can throw any number of exceptions.
If your buddy decides to throw a new exception in some helper function then
the exception signature of a hundred functions changes.

So basically, there's no way of telling whether the code is correct. Good luck
with that. So people give up and just rescue every possible error and return a
default value, excactly like described in the article.

For your enjoyment:

[http://www.google.com/codesearch?q=lang%3Aruby+rescue&hl...](http://www.google.com/codesearch?q=lang%3Aruby+rescue&hl=en&btnG=Search+Code)

And this is _production_ code you're looking at.

~~~
BrandonM
_If you don't check a pointer before dereferencing it - the code is wrong._

Really? This might be true after a malloc or another system call, but in
general, your modules should have specifications. If you have written a
function which states that the incoming value must be a pointer to some value,
that pointer shoud _never_ be checked before dereferencing it. It's the
caller's job to ensure that a valid pointer is sent.

Blindly checking for errors that will never come up is not much better than
not checking at all.

------
gcv
Exceptions in mainstream languages have a fatal flaw: they unconditionally
unwind the stack when thrown. This sacrifices flexibility and makes it
unnecessarily difficult to save state or take action at the point of the
throw. Of all languages I've ever seen, only Common Lisp really does this
right by separating out the concept of signaling a condition and of handling
it.

I don't want to get into the details here, but Kent Pitman wrote a great paper
on the subject: [http://www.nhplace.com/kent/Papers/Condition-
Handling-2001.h...](http://www.nhplace.com/kent/Papers/Condition-
Handling-2001.html)

------
jrockway
I think his article should be called "unexpected errors suck". Sure, it would
be nice if there were never any errors, but there are, and you have to handle
them somehow. Compare:

    
    
       try {
          connect_to_database;
          prepare_query("SELECT * FROM ...");
          run_query;
          return results;
       }
       catch database error {
          warn "Whoa, your database is broken!";
       }
    

To a language without exceptions:

    
    
       dbh = connect_to_database;
       if(!dbh){
          errno = 0x23843;
          return NULL;
       }
       statement = prepare_query;
       if(!statement){
          errno = 0x28783;
          return NULL;
       }
    

At this point, I'm tired of typing the code. Checking for errors after every
function call is way too much work, especially if future instructions need to
past ones to have been successful. Exceptions let me break right out of the
related block, and do something to fix it. If I don't do something to fix it,
someone up the call stack can fix it.

I don't think exceptions suck. Errors are what suck.

~~~
Retric
The problem with the above code is without exceptions you know where the
program failed 23843 or 28783 but with exceptions all you know is something is
wrong.

~~~
aggieben
bzzt. depending on the language and the author of the exception-throwing code,
the exception will contain information about where the error occurred and what
might have caused it.

~~~
Retric
True, but in the above code such information is not propagated outside of the
function. If you want to add that you need to throw another exception inside
of the catch block or skip the catch.

~~~
natrius
Which is exactly the right thing to do. I don't see the problem.

~~~
Retric
_At this point, I'm tired of typing the code. Checking for errors after every
function call is way too much work_

Think of what the exception code ends up as in ASM. Basically _try_
transparently wraps system calls with the same type of error handling code as
his example. However, if you want to write stable code you need to account for
each of these errors anyway. So when your DB connection fails you need to know
if it’s a TCP/IP error or a Bad Password etc which means either wrapping each
line with its own try catch or decoding the exception within a catch block.
Granted, exception handling let’s your write code for the ideal case and avoid
crashing when something messes up but as soon as you want to recover from an
error without starting over you end up writing the same code anyway. And
because the happy path works it’s not obvious just how far you are from high
quality code.

~~~
aggieben
See my later comment about expected errors versus unexpected ones. Exceptions
were never meant to replace good error-handling code.

------
DaniFong
Exceptions suck, but I really think this is going the wrong way.

Exceptions usually suck because people are trying to graft some kind of
complicated event handling system on it, to which it's not suited. Frankly,
this sort of thing is better handled by co-routines. Exceptions suck because
they're the often the only way to do something without more explicit control
flow.

On top of this, we're supposed to be able to check everything and write error
checked code, but suppressing errors can be surprisingly beneficial: observe,
say, DRYing out deep checks <http://code.causes.com/blog/drying-out-deep-
checks>.

One of the reasons GOTO sucked so much was because at the time it was all we
had. Now it isn't. Explicit control flow is useful and important for certain
tasks (like network programming).

------
aggieben
This kind of argument also seems to miss something important: that exceptions
(at least in C++, but this argument probably applies to other languages as
well) aren't intended as a general-purpose error-handling mechanism, which
return codes are perfectly adequate for.

Exceptions are intended for unexpected conditions (i.e., exceptional) that
must be handled somehow. In C++, this is pretty fundamental to the RAII idea.

------
arockwell
I agree with his premise that exceptions get misused by "average" developers.
Where I work I see _a lot_ of swallowed exception, which has lead to some evil
bugs. I have also encountered some code that's literally impossible to write
meaningful test code for because every exception is swallowed and there's no
return code.

However, I don't think that going back to checking return codes solves
anything. Most of the problems I see at work are related more to checked
exceptions than using exceptions in general. Thankfully, most of java
frameworks I use have moved towards making everything an unchecked exception.

~~~
jrockway
I only write Java on very rare occasions (usually for clients that don't care
if the code is throw-away quality), and so I usually end up with a "throws
Exception" after every method. Horrible, but hey... it's not _my_ fault Java
sucks so hard.

~~~
ajross
No offense, but yeah: that's pretty horrible. Checked exceptions are one of
Java's few true innovations. Used properly, they force you to handle errors in
the spots where they occur. What you're doing is a 1:1 equivalent of ignoring
the error codes returned from your C functions. That's just never the right
way to do thing.

~~~
wvenable
Exceptions are not meant to be handled where they occur, that's why they
unroll the stack. For the most part, you can't recover from an exception --
you just abort whatever you're doing, print an error message, and let the user
try something else. Checked exceptions cause developers to re-interpret the
exceptions or just swallow them -- neither is a benefit.

~~~
jrockway
Exactly. If the database server blew up, there's nothing my program can do. I
could try reconnecting, and some libraries do, but that doesn't usually help
anything. Once the server is back up, the Fibonacci (or exponential) back-off
is so high that's it's faster to just restart the program manually. So
usually, dying is easier for everyone.

------
IsaacSchlueter
The problem with exceptions is that most developers using them don't use them
well, which does kind of mean that they should be avoided if you're not sure
you need it. But I don't think that they have no place in running code. (Since
I write mostly Javascript, try/catch is so expensive that it's usually not
worth it, especially if you build your site so that it works when the JS
doesn't, which is just good practice.)

I recently came across something like this, which struck me as a horrendous
abuse of "exception" handling:

    
    
      // drastically simplified so as to not make anyone nauseous/crazy:
    
      try {
        $x = doSomething();
        doSomethingElse($x);
        if (!$x->foo) {
          $x->foo = "bar";
          throw new NoFooException($x);
        }
        doSomeMoreThings($x);
      } catch NoFooException {
        handleNoFooCase($x);
      }
    

Not 10 lines later, in the same function:

    
    
      do {
        ...bunch of code.
        if (!$x) {
          break;
        }
        bunch more code.
        if (!$y) {
          break;
        }
        bunch more code.
      } while(false);
    

followed by new fewer than 3 other "clever" control constructs.

Frankly, GOTOs would have been easier to follow.

------
narag
I have lived this kind of crap before. New job. The boss has some fringe idea
that makes life more difficult for everybody. But until now I haven't seen
this. Exceptions suck. Yeah, sure.

------
ricky_clarkson
Exceptions suck. Prefer monads.

------
st3fan
"""Can't this be fixed by hiring better developers?"""

The answer is _yes_.

------
BrandonM
I personally thought the article was garbage. The author rehashed a lot of old
ideas and lumped together a bunch of anecdotes without giving much new
insight.

The thing that really bothered me is that I got the distinct feeling that the
author is only parroting old advice, without actually trying anything himself.

In particular, he said that exceptions are expensive in any language. In
Python in particular, exceptions are no more expensive than any other control
structure, as that was an explicit design decision.

Exceptions _work_ , that's all there is to it, but they _have_ to be
documented. The Python documentation is a very good example of this. For the
built-ins in particular, every single operation states what type of exception
is thrown in what case.

Exceptions can be very effective if:

1\. Each function/method documents what exceptions it throws under what
circumstances.

2\. Exception causes are thoughtfully separated into different types. One
example of a violation of this principle that has frustrated me recently is
Python's os.makedirs function, which recursively creates a hierarchy of
directories. This can cause an exception if one of the directories cannot be
created for some reason (permissions, desired directory is an existing file,
etc.) or if the leaf directory already exists. In some cases, the latter case
really is not an error (you just want "mkdir -p" functionality), but it's hard
to distinguish between the two cases.

3\. The proper exceptions are caught. Too often programmers attempt to catch
every exception and re-propagate it (or worse, ignore it). In many cases,
exceptions are only meaningful during debugging, and once minor issues are
worked out, the exceptional case is guaranteed to never occur. These types
_should be allowed to propagate to the top-level and crash the program_ , that
is the whole point of the exception. In other cases, the programmer needs to
be aware of what exceptions may occur (see 1), to reason about how such cases
should be handled (if at all, perhaps allowing it to pass up the stack makes
sense), and to handle it appropriately. Only in a top-level logger for a long-
running program should a catch-all exception ever be used.

...and that turned out much longer than I initially planned. I am just tired
of hearing the same old "exceptions are bad because people will use them to
mask real errors" argument repeated over-and-over, when no programmer worth
anything would ever do that. Also, this popular comparison of exceptions to
GOTOs is ridiculous. The article on GOTOs was written at a time when spaghetti
code which jumped all over the place to save repetition was not at all
uncommon. Thanks to more recent constructs like do...while, break, continue,
for loops, function objects, and more, crazy "old school" code patterns are
much less common. To march that argument out today any time someone dislikes a
given control flow structure is a disservice to the original paper (which was
actually addressing _real_ problems in code structure), because the comparison
invariably is between apples and oranges.

------
kingkongrevenge
Except for the point about exceptions being like GOTO, I fail to see how any
of this differs from the complexities of procedurally handling return code
errors. Exceptions give you a better way to distinguish error handling from
control flow.

I'm not even sure I understand how GOTO is unmitigated evil. Occasionally it
can be the clearest way to break out of a nested loop. Doesn't the Evil GOTO
song and dance come from an ancient era when it played a completely different
role in languages?

~~~
edw519
_Doesn't the Evil GOTO song and dance come from an ancient era_

The languages may be ancient, but the era is not.

I'd be willing to bet more than half the production code running now has
ancient GOTO capability and half of that is misusing it.

(Apologies to Churchill) Never was so much earned by so many maintenance
programmers from the misuse of so few letters.

------
omouse
Flagged. What a shit post.

This is mostly a complaint about shitty developers than about exceptions.

