Fog Creek Software
Discussion Board




Confused about exceptions vs. status returns

I don't understand the fuss about exceptions *versus* status returns.  What does that mean?

I first learned about exceptions from Python, where they are implemented...  guess how?  Using status returns!

Python is written in C.  C has no exception mechanism.  So, Python uses status return values to indicate an exception at the C level.

Python's higher-level code constructs are all implemented by calling these C functions that check for error returns.  In a block of code, any error return that isn't otherwise handled, causes the block to return the same error status to the caller.  And so it goes, until somebody handles the status return.

So, how is that *different*?  I've seen two arguments here:

1. It makes things crash
2. It makes it hard to see what's happening

Given my understanding of exceptions as a form of return code checking, I am completely unable to understand argument 1.

For argument 2, I fail to see how saying, "any error return I don't explicitly check for causes an immediate return of the same error to my caller" somehow makes the code's behavior "non-local".

Perhaps those putting forth argument 2 are claiming that the absence of visible status checking causes them to assume that no errors can take place in that code.  To me, that seems dangerous, because *all code can fail unexpectedly*.  Therefore *all* procedure returns must be checked for failure, "without exception".

So, if *all* returns must be checked for failure, and the reasonable thing to do in most cases is to pass the buck to your caller (perhaps using a different error code, perhaps cleaning up a bit first), then why on earth should I have to write that if-then check *after every single function call I make*?  Doesn't it make more sense to let the language check for me?  Then, I only have to write code for the case where I specifically want to do something different.

My experience with exceptions is that it forces me to think about the possibility that they can occur *everywhere*, whether a routine has an explicit return status or not.  Conversely, my experience programming in languages where exceptions don't exist, is that sooner or later somebody forgets to check the return value, because you have the *option of not doing so*.

Thank goodness there are languages that will provide a sensible default behavior in the event that you forget to check for a particular error, and also allow you to put a top-level error handler in your main loop or function to catch any of those status checks that you forgot to write.

Phillip J. Eby
Thursday, October 16, 2003

The issue is not that you can understand what you have done as you are doing it.  The issue is can someone else (or even yourself after significant time has passed)easily understand what you did from your source code. 

If the exception causes an invisible transfer of program sequence to some distant chunk of code, it cannot be understood from the local information.  One must break one's focus and look god knows where to find the code that is to be executed in the case of an exception.  No amount of external documentation can fix that problem either because looking at external documentaion is an instance breaking one's focus as well.

A break in focus is the same as any interruption.  No matter how brilliant you are, you can only hold so much complexity in your foreground mental processes.  The hold on that complexity fades quite rapidly with the breaking of focus.  Time and effort must be spent re-establishing that hold.  The time can be as much as 30 minutes if the interruption is more than a very minor one.

The question is how productive  do you want to be?  If you want to produce the so called standard 10 lines of code per day, do it whatever way you wish.  If you want to compete, its just likely you will want to consider doing things in a very different way.

Lionell Griffith
Thursday, October 16, 2003

I'm still confused.  In a language with exceptions, every procedure invocation effectively has this:

if error_returned:
    return error_returned

implicitly written after it, *unless* the function call is in an explicitly marked (and probably indented) error-catching block.

If you wrote this out by hand, would you call it a "transfer to some distant chunk of code"?  It's a *return statement*, for goodness sake.

Now, I get that it's invisible, but since it happens after *every* function return in a language that has exceptions, why on earth would you as a reader of that language think that it's *not* there?

Phillip J. Eby
Thursday, October 16, 2003

Lionell Griffith takes a break from insulting everyone else to write:

"The issue is not that you can understand what you have done as you are doing it.  The issue is can someone else (or even yourself after significant time has passed)easily understand what you did from your source code."

I agree completely that good code should communicate to other programmers. I never wrote anything to the contrary. Good code is usually succint code--just what you need to do the job and nothing more. I don't have any problem reading code I didn't write even if it uses exceptions because I understand how exceptions work and where to look for the handlers. When writing code I assume that other programmers will read it, but I also assume those other programmers will understand the language more or less as well as I do; I don't avoid language features because someone else might not understand them.

"If the exception causes an invisible transfer of program sequence to some distant chunk of code, it cannot be understood from the local information.  One must break one's focus and look god knows where to find the code that is to be executed in the case of an exception."

You're just wrong on this. You look for the exception handler by walking back up the call stack. A good IDE or debugger can do that for you, or you can look at the stack dump the exception mechanisum provides. The exception handler may not be local but it isn't in some random mysterious place, either.

The alternative is to catch all errors and deal with them locally. That is practical for some kinds of problems, and when that's the best way that's what you should do. For example, if I were writing a function to calculate the average of an array of numbers, I'd have to account for the possibility of zero entries. To avoid a divide-by-zero exception I might decide to just make the average zero--whether that's better than throwing an exception or returning an error code depends on the context and importance of the function.

If I'm looking at code I didn't write and come across this:

  x = a / b;

I will look around to see if the code checks anywhere to make sure b isn't 0. If I don't see the check I know that the run-time system will throw an exception if b is ever 0 (assuming a language that uses exceptions, of course). So do I have to look at all of the source code to see if this is handled? No--I just have to look at places that call this function. I'd have to do that anyway if I was fixing a bug in the function.

You're right about breaks in concentration and the desirability of keeping information local when possible. But it's not always practical to have every low-level function deal with every error it may encounter. It has to report the problem back to its caller. Those errors have to propagate back up the call chain. You can do that with return codes, but it's messy (and the information is not localized anyway). Or you can do it with exceptions. Both techniques have their place--it's not an all or nothing decision.

I tend to not throw exceptions in my own code, but I do catch exceptions from functions I call.

You make good points but your tendency to insult everyone else and make assumptions about their skills and motivations is off-putting.

Gregory Jorgensen
Thursday, October 16, 2003

> One must break one's focus and look god knows where to find the code that is to be executed in the case of an exception. 

What I'm hearing is that exceptions break your own flow, and so you don't like them.

Not everyone feels that way, and I think you are over-generalizing from your own experience.

> If you want to compete, its just likely you will want to consider doing things in a very different way.

This is a "special snowflake" argument, and will get you dogged mercilessly on this board. Please stick to the merits of your case.

Portabella
Thursday, October 16, 2003

  x = a / b;

with double in C++, is this even sure to throw, when b==0?  Or might you just get NAN?

Keith Wright
Thursday, October 16, 2003

No.

5.6p4 ( Multiplicative Operators )

"The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second.  If the second operand of / or % is zero the behavior is undefined."

Danil
Thursday, October 16, 2003

*  Recent Topics

*  Fog Creek Home