Avoid Exceptions Whenever Possible

Seems like something that will come back to bite you. Aren't exceptions like const-correctness or preemptive multithreading - great if you design 'em in, horrible if you try to retrofit? Some call them "GoTo resurrected".

Exceptions are actually easier to retrofit into code than alternatives like error code returns. Ideally, your code should not return errors, but in cases where it does or must, exceptions appear to be the simplest, most reliable way to implement an error return.


In my experience, it is best to avoid exceptions whenever possible. They complicate your thinking, complicate the code, and make debugging a nightmare.

Just say no.

That said, some patterns for how to use them well will be welcome and interesting ... I hope some turn up! -- RonJeffries

I agree. -- MichaelFeathers

I propose this:

 try: foo_index = mycoll.findFirst( "foo" )
 except NotFound: ...

instead of:

 foo_index = mycoll.findFirst( "foo" )
 if foo_index < 0: ...
The reason is that it does not make sense to come up with arbitrary "error values" that have horrible effects if not checked. An uncaught exception can be found out automatically via syntactic support (exception checking) or exception inference. -- PanuKalliokoski

Perhaps if languages allowed multiple return values (kind of like Python), then such would not be an issue:

  (result, err) = doSomething(...);
  if (err) {message("your foo is all barred-up");}

Or, return an object or map:

  result = doSomething(...)
  if (result.err) {message("your foo is all barred-up");}

Somewhere around here I remember discussing even more alternatives, but haven't found it yet.

ForthLanguage does this. For example, many of the File words which might fail return both data results as well as an "io-result" flag indicating overall success or failure. The caller can then choose to test it or rethrow it as an exception.


The rule here is that exceptions should never be expected. Any forseeable exception should be avoided beforehand. The reasoning is twofold: one, this eases debugging. Most IDEs can break on the moment "throw" operation is detected, making it easy to find the first site of an error. Masking "expected" exceptions then becomes a frustrating task. Second: exceptions are really, really slow in most languages. And not slow as in "a couple of extra branches" slow. Slow as in "significant impact compared to string processing and dictionary-lookup operations". Of course, one must balance that problem against the risks of PrematureOptimization. Unfortunately, exceptions also serve useful secondary functionality (breaking out of loops, non-expected-return-type returns, etc.) so hopefully languages will in the future allow different approaches to the "try/catch/throw/finally" system to allow it's more "creative" applications. --MartinZarate


Possible JavaIdiom:

I remember reading in ByteMagazine that some people use exceptions to break out of loops in Java. Embed the whole loop in a try block.(This reduces the number of operations needed to evaluate the loop condition.) Apparently on a Sun JVM it made the code faster, but on the Microsoft JVM it was relatively slower - still, you can use it on server-side code.


You'd think Java had a break statement...

I know this must have been written a long time ago, but in hindsight it's a godawful example of PrematureOptimization.


I'm not at all certain I agree with the subject of this page, but I do think exceptions shouldn't be used in lieu of a simple break statement. There are other control uses where they're much more likely:

As to the subject of the page, I don't think you can really AvoidExceptionsWheneverPossible these days - not when the standard libraries all throw 'em. Maybe the Smalltalkers can still get away without exceptions, but the rest of us are stuck with 'em and need some rational strategy for using 'em. -- PeterMerel


I'm not sure what is being proposed as the alternative to exceptions. Return an error value? But how do you ensure the caller checks it? And shouldn't the function return value be used for something more interesting, like its result? Passing in a parameter to be filled with the (possible) error value is syntactically nasty and messes up the caller (who now has to allocate the object). Eiher way seems to make for more complicated code rather than less, and it becomes harder to separate out the error handling.

But sometimes you don't want to check the error value. The whole point of the NullCatchClause pattern - a pattern that really does occur in nature - is that you have to do ugly things to handle an error some fool library writer thought was important. If Thread.sleep(int) simply returned an indication of whether it was interrupted, a lot of noise could be eliminated from what should be simple code.

:
I think the whole point of exceptions is that it's harder to ignore them, because ignoring exceptional conditions is easily responsible for some 90% of error handling failures.

::That would only eliminate noise if you didn't check the return value, and therefore didn't handle the exceptional condition, an interruption -- ChrisMosher?.


See SmalltalkAndExceptions.


But anyway, I disagree with Ron. I think that you should use exceptions for exactly the reasons that Dave gives. In fact, let's make it a new pattern called UseExceptionsInsteadOfErrorValues

KyleBrown


I have to second Ron on this. Stripped of its name, the construct that we know as an "Exception" is really a big non-local goto. I tend to feel that people should do the same amount of grave thinking before using exceptions that we hope they do before using gotos. Why? Well, an exception is a goto. In spite of that, there are a few cases where they are worthwhile.

It might be better to say that both exceptions and gotos are specialized forms of continuations - specifically, an exception is a dynamically scoped forward continuation which carries specific information about the code which it continues from. (Of course, some may argue that full continuation are worse than gotos, but that's neither here nor there.) Also, just as such specialized forward goto forms as break and continue are more structured than unrestricted gotos, exceptions are more structured than unrestricted continuations - they can only transfer control to an enclosing handler. -- JayOsako

Exceptions are no more gotos than are loops -- in fact less so, since loops generally are implemented as gotos (or jumps), whereas exceptions are not. In fact, exceptions are no more gotos than function returns are -- and are implemented similarly. Saying that exceptions are gotos reflects a gross failure to conceptually abstract ... what all these features have in common is that they are transfers of control, but there's nothing wrong with those per se and they can't be avoided. There are problems with exceptions as there are problems with everything, but let's try to be accurate and sensible. -- MarcelKincaid?

Exceptions are for handling the following situation: you can not find out in advance whether an operation will succeed without trying it. The wonderful thing is, that most of the time in programming you can find out whether an operation will succeed before trying it. If you are the one writing the code, you write it so that it will work. If you are using someone else's library, you test and check the docs to see if it will do what you want.

There are times when you can not know in advance whether an operation will fail. Most of these situations occur when you are interacting with entities outside the system (outside your control). I/O is one example. Memory exhaustion is another. JUnit and CppUnit use exceptions because the tests that are to be run are not known in advance. They are from "outside" the system.

As an exercise, every time that you think of using an exception in violation of the criterion I gave above, imagine what you would do if you didn't have them. You would probably end up writing more code, but you would also be writing it in a way where you are guaranteed that it will work. You end up with fewer alternate courses. You are making your code more deterministic and you can pass your tests more directly. It will be simpler to understand.

An error log is an alternative to complex error return values. If you have a common base class in a system, add a reference to an error log object.You can then ask objects about errors that have been accumulated.

To me, exceptions are for handling situations in your program that you can not control. The fact is, most of the time we have more control than we will admit to.

-- MichaelFeathers

This is a lot of useless handwaving. Aside from the log object, it provides no guidance for eliminating existing exceptions or checking error return value. And the log object doesn't do the trick because ... when does one check it? Exceptions and checking error return values happen sequentially, between the error and the execution of code that cannot tolerate the error; log objects serve a very different purpose, of reporting what errors occurred, for analysis -- they are totally the wrong thing, functionally and conceptually, for the purpose of conditionally executing code only when errors have not occurred. There are objects suitable for this purpose, as seen in functional languages like Haskell or Scala -- objects that box either a value or a (possibly chain of) error indicator. Any function on such an object returns a new object that boxes either the function performed on the value or the error indicator (possibly replacing it with a more specific indicator or chaining another indicator to it). This is logically equivalent to checking error return codes (vs. exceptions) but errors can't be ignored ... the type system doesn't allow it. -- Marcus Kincaid


Maybe it's my Ada background, but I think exceptions (when used correctly) are wonderful.

First, if the code you are interfacing with raises/throws exceptions, you (mostly) should catch them rather than prevent them. The validity checking occurs OnceAndOnlyOnce.

Second, it makes the code simpler by visibly separating the general case of expected processing from the special cases of errors. It is a mess tracing through nested if-then-elses resulting from different errors revealed in the processing of inputs.

I see this a lot where I work. It is not necessary to have a tower-of-if just to do error checking. Writing plain, flat code is possible, and does not in fact (contrary to belief) require exceptions. ArrowAntiPattern code (the aforementioned tower-of-if) is a *HUGE* CodeSmell.

Third, I think exceptions are as similar to gotos as loops and branches are. All three change the execution point. All have well defined concepts and rules behind them.

-- WayneCarson


One way to avoid throwing exceptions is to use the MissingObject? pattern, which, in sum, answers an object which will benignly carry on, accepting whatever messages will be sent to it and doing nothing harmful. It doesn't always apply, but when it does apply, it's cleaner by far. -- RonJeffries

I think that MissingObject? is probably the same as NullObject, as defined in PatternLanguagesOfProgramDesign-3 (which seems different from the NullObject here on Wiki).


As an experiment, write some code as if no exceptions could occur. Then change the code (or rewrite it if that is your wont) to support exceptions. Then read the code and decide which is more clear. If you think the exception code is more clear, please post it. If it isn't, subscribe to the point of this page. -- RonJeffries

(That's exactly why I write code that uses exceptions: It allows me to write "as if" no errors could occur - when, in fact, just about any of the function calls could fail. Writing code to explicitly handle each and every "almost impossible" error condition would be very tedious. -- JeffGrigg)

Indeed. How absurd/unfair to compare code that ignores errors with code that handles them via exceptions. The proper comparison is between code that handles errors via some means other than exceptions and code that handles errors via exceptions. Unless you're writing functionally in something like Haskell or Scala where you can enforce seamless error checking via the type system, the code with exceptions will invariably be clearer ... and far less likely to ignore errors, failing far from the cause of the error with no trace. -- MarcelKincaid?


Getting a little pushy, Ron? (-:

[Exceptions] makes the code simpler by visibly separating the general case of expected processing from the special cases of errors. -- WayneCarson

Well, yes, in the small, the exceptions do help separate out the exceptional case of the code (imagine that), but it becomes a problem as your code starts to get deeper call chains, and especially if you apply ThrowDontCatch. When you start to have all these exceptions flying around, every object that might pass through an exception has to worry about which statements might throw an exception, and what might need to be cleaned up in order to fix the problem. In practical terms, this means that your code starts to get littered with "finally"s (or 'unwind-protect's or whatever you want to call them) as you allow exceptions to be thrown through objects that need to keep their state consistent despite the exception.

I think exceptions are as similar to gotos as loops and branches are. All three change the execution point. All have well defined concepts and rules behind them.

The same could be said about goto statements - it's been a while, but I can imagine what the denotational semantics would look like (and they ain't pretty). (-:/2

Whoosh! The point is a rebuttal to the absurd claim that exceptions are gotos. Sure goto is a well defined concept, but rules? What rules? That's the whole point -- exceptions, loops, conditionals are constrained in ways that goto isn't. And the statement below that even intraprocedural gotos can be understood simply by inspecting the procedure is absurd -- one can view a binary executable as one large procedure; all control flow can be emulated with goto. Good luck inspecting and understanding ... and getting your solution to the haling problem published. Folks attacking exceptions need to think more clearly ... and intellectually honestly. -- MarcelKincaid?

Furthermore, exceptions are conceptually and computationally more difficult to analyze because they depend on the program's runtime behavior. Loops and branches, and even intraprocedural gotos, can be understood simply by inspecting the procedure in which they appear. Exception handling depends on call the dynamic call graph - you might get an object in a class that will throw an exception one time and a different subclass that won't some other time. (Yikes! I think I am actually managing to convince myself!)

Anyhow, exceptions are more of a ComeFrom than a GoTo. The catch clause knows where it is, but the throw statement has no idea where the flow of control will end up - it's just a "go".


The topic phrasing here, AvoidExceptionsWheneverPossible, seems to be attracting the polarized discussions typical of such strongly worded maxims.

Is the idea that the throw/catch programming construct (or the like) should be avoided in almost all circumstances where it might be used, in much the same way that goto constructs are; or rather that that construct should be reserved for exceptional conditions (rather than being used for the normal termination of a loop)? -- JimPerry

[Jim's subsequent discussion moved to ExceptionsAreOurFriends]


Yes, predicting the dynamic execution of code from its static representation can be difficult, and exceptions don't make it easier, but I believe exception-based code is easier to read (and predict) than alternatives with similar behavior.

I think exceptions could be modeled with nonlocal gotos to label variables (I'm thinking PL/I, which also provides similar signal/condition), which can in turn be modeled with C setjmp/longjmp (ignoring destructor behavior in C++ for the moment).

I seem to recall that comefrom is equivalent to goto or such at least was the claim long ago (I recall a program which would convert a GOTO-based program into an equivalent COMEFROM-based one). -- JimPerry

I don't think exceptions are easy to equate with comefrom, though perhaps someone here with InterCal experience would think otherwise. I think JimPerry's example should be enough for Ron, and to refute the title of this page. So can we all agree that exceptions are good; ExceptionsAreOurFriends.

That said, the next question is, when should we avoid exceptions? Many folk say DontUseExceptionsForFlowControl, but this seems too broad in light of their very handy use as a way to quench recursion and threads. What we need is a reason not to use them - a constructive criterion rather than a blanket "avoid" directive. -- PeterMerel


I'll stand by my opinion, which overlaps JimPerry's a bit. Exceptions are for the cases where the only way to know whether an operation will succeed is by trying it. These tend to be the areas of a system which touch the outside world.. things outside of our control.

If you want an additional constructive criterion, I'd say only use them when you are sure that you can rollback every state change you are interested in that occurred from the point of the catch to the throw. Just remember YouDontWantAnExceptionYouWantaTimeMachine.

Peter, I don't understand your cases. I've written recursive descent parsers and very thread intensive code, and I haven't been tempted to use exceptions.

-- MichaelFeathers

Oh, you can certainly write recursive descent parsers without using exceptions! I used them there mainly because I was curious about what they'd be like if you did use them as full-fledged control structures. So I wrote like that and kind of liked it. I didn't run into any glaring maintenance problems, so I began to wonder just what the fuss was about. I'm still trying to figure out what the fuss is about.

See Also ExceptionsTidyThreads


Exceptions are a particularly nice model for syntax error recovery in a recursive descent parser, especially for grammars with some degree of hierarchy (like many programming languages). Parsing errors at the expression level can throw something which will be caught at the statement level (or whatever) which may be able to resynchronize and continue.

BTW, I find I went from recursive descent years ago, to yacc/lex, to ANTLR, back to hand-coded recursive descent. -- JimPerry


"Exceptions are for handling the following situation: you can not find out in advance whether an operation will succeed without trying it." - First I note that this criteria applies equally well to returning an error code. That aside...

Let's say I can find out in advance. So I write two methods, say canInvert() and invert(). Then I write code like:

if (matrix.canInvert())
matrix.invert();
Let's further say I have code like this in 20 different places. Doesn't it make sense to refactor, and have a single routine like:
void invertIfPossible() throws CantDoItException? {
if (self.canInvert())
self.invert();
else
throw new CantDoItException?();
}
? (We could also return an error code, but that's orthogonal to the point I'm discussing.) Is this refactoring bad somehow? -- DaveHarris

As a refactoring per se, it does not look like a bright idea, because now you are going to have to run around dealing with this new exception every place a matrix gets inverted.

An alternative:

boolean invertOrNot() {
if (!self.canInvert()) return false;
this.invert();
return true;
}


I'm trying to help. A thing that usually works is grounds for an exception when it doesn't. If I expect that all my matrices are invertible, then the exception structure makes sense because my normal usage is just to go ahead and invert. If OTOH my matrices are all over the map, then my normal usage is probably more like the conditional form.

Two things that often happen with exceptions lead me to AvoidExceptionsWheneverPossible: ExceptionsMaskRealProblems, and the lack of ExceptionHandlingNearMainline.


Maybe I'm missing something.

It seems that error status and exceptions are in similar boats. Error status says, there was a problem. If anyone cares, they have to put in some code to check it. Otherwise the program will hobble on.

Exceptions say, there was a problem. Someone must deal with it. If you won't deal with it, I'll find someone who will.

Exceptions have an additional advantage over returning error status for functions. Since most current language support only a single return value, you don't want waste it on error status. You are not forced to procedurize your routines (for the exceptional cases).

function Invert() return float;
function Determinant() return float;

procedure someTransformation() is Matrix matrixIn; Matrix matrixOut; begin Read(matrixIn, "SomeFile?"); matrixOut = Determinant(matrixIn)*Inverse(matrixIn); Write(matrixOut,"SomeOtherFile?"); exception when DeterminantOutOfBounds? => raise InvalidInput?; when MatrixNotInvertible? => raise InvalidInput?; end;
Some logging should be done too (in the exception handler). Does someone want to rewrite this without exceptions? -- WayneCarson

Make it part of the standard error message, perhaps with a parameter to skip logging if desired:

  if (err) {exceptionMessage("It broke, you're fired!", log=false);}

Here, logging would be on by default but can be bypassed via an extra parameter.


Thanks for helping me clarify what I believe. If I understand the language, I would write the above this way without exceptions:

function Invert() return float;
function Determinant() return float;

procedure someTransformation() is Matrix matrixIn; Matrix matrixOut; begin Read(matrixIn, "SomeFile?"); matrixOut = Determinant(matrixIn)*Inverse(matrixIn); Write(matrixOut,"SomeOtherFile?"); end;
This example shows just where I've been coming from: to me, the code is more clear without the exception lines, which are just exchanging one exception for another anyway.

In other words, if the program were going to compute a wrong answer, we'd have to use an exception or an error check (and for this example might prefer the exception). But since this program, if I understand it, is going to blow anyway, I feel that transforming the exception may not be worth the trouble.

In the words of the old man marrying the young woman ... if she dies, she dies. -- RonJeffries


I guess I see there is a hierarchy of caring. The Determinant and Inverse functions should log the contexts the error occurred in, someTransformation should log the context the errors occurred in, etc. The caller to SomeTransformation? doesn't care why it failed. It wants to know that it did fail (by handling the exception), log it, and move on. The caller may look like

procedure Caller is
begin
loop
wait 5.0;
begin
RequestMatrix?;
SomeTransformation?;
exception
when MatrixServerDown? => 
Log("Matrix Server Down");
WaitForMatrixServer?;
when InvalidInput? => Log("Invalid data at "&Time);
end;
end loop;
end;
The example was made more for comparison to error status.

-- WayneCarson


Here's an example of exceptions making code simpler. The equivalent structured code that also handles error conditions properly is more complex. _ _ _ _ _

This is the original function, with a few minor changes: Invert() returns an inverted matrix, not a float. (Otherwise matrixOut would be a float, not a matrix.) I added [in]/[out] notation for parameters and "throws" clauses to the functions, to clarify the interfaces. -- JeffGrigg

 function Invert() return Matrix throws MatrixNotInvertible?;
function Determinant() return float throws DeterminantOutOfBounds?;

procedure someTransformation() throws InvalidInput? is [in] Matrix matrixIn; [out] Matrix matrixOut; begin Read(matrixIn, "SomeFile?"); matrixOut = Determinant(matrixIn)*Inverse(matrixIn); Write(matrixOut,"SomeOtherFile?"); exception when DeterminantOutOfBounds? => raise InvalidInput?; when MatrixNotInvertible? => raise InvalidInput?; end;
_ _ _ _ _

This is how JeffGrigg would write the code - with exceptions. I dropped the ConvertExceptions idiom, which I think should be used to add context information. I introduced BaseErrorClass?, as a parent of the other exception classes.

 function Invert() return Matrix throws MatrixNotInvertible?;
function Determinant() return float throws DeterminantOutOfBounds?;

procedure someTransformation() throws BaseErrorClass? is [in] Matrix matrixIn; [out] Matrix matrixOut; begin // This code is "ExceptionSafe?." Read(matrixIn, "SomeFile?"); matrixOut = Determinant(matrixIn)*Inverse(matrixIn); Write(matrixOut,"SomeOtherFile?"); end;
_ _ _ _ _

This is a reasonable way to write the code without exceptions:

 function Invert() return int /* errorNumber */ is
[in] Matrix matrixIn;
[out] Matrix invertedMatrix;
...
function Determinant() return /* errorNumber */ int;
[in] Matrix matrixIn;
[out] float inversion;
...

function someTransformation() return int /* errorNumber */ is [in] Matrix matrixIn; [out] Matrix matrixOut; begin float determinantValue; Matrix invertedMatrix; someTransformation = 0;// assume success, until failure Read(matrixIn, "SomeFile?"); if Determinant(matrixIn, determinantValue) = 0 then if Inverse(matrixIn, invertedMatrix) = 0 then matrixOut = determinantValue*invertedMatrix; Write(matrixOut,"SomeOtherFile?"); else someTransformation = errorInvalidInputConstant; end if else someTransformation = errorInvalidInputConstant; end if end;
Here are some issues: #1. Invert() and Determinant() can no longer return the "natural" results of their functions, as the caller must check for errors before using a possibly invalid result object. #2. Can't get rid of the if statements, even if we just want to pass errors up to our caller, unchanged. (A common solution is to use "return" statements, violating structured programming rules.) #3. More local variables are needed. #4. How can we determine if the multiply operation (float * Matrix) fails? Do we return a NullObject and/or check an error flag?


Another example. Suppose a floppy disk write fails. You may need to know whether that is because of a basic problem with the integrity of the hardware, or if it's just a full disk. In the one case you sound alarms bells and halt, the other you calmly ask for another disk.

There are many situations where it is not enough to know that something failed; you also need to know why. How best to communicate this? You could use integer IDs, but that isn't very extensible. Using single integer forces you to classify groups of errors by using subranges. You have to ensure that different hardware manufacturers don't use the same subrange for different things. You have no-where to put auxiliary information, such as the name of the file involved.

Returning a string is better in some ways, but may mean you report "File xf213861 not found" when you really mean, "Database not created yet". It's harder to do stuff with strings programmatically. Bits of code end up parsing each other's error messages.

Exceptions allow you to use arbitrary objects. You know it makes sense. -- DaveHarris

My take on what DaveHarris is trying to say is that with exceptions typically give you the full power of the inheritance mechanism for your error information. I've worked on a large C/C++ project (using an old DOS compiler, so no exceptions, templates or other trendy features) which hit real problems with standardizing on IntegerErrorCodes?.

The first problem was that _every_ function or method in effect became just a "procedure". The return value was reserved for the error code. This caused all sorts of jumping through hoops to get data out of the call.

The second problem was that the style quickly became "every call must return an error code, even if it is always SUCCESS". This is iniquitous and leads to a *lot* of pointless conditionals and error handling in other code which treats calls to other modules as a "black box". The alternative to this was to ignore the error value, which also caused problems if the "black box" was changed to actually return an error - catch 22. (OK, this is a Refactoring problem...)

The third problem was a massive confusion of error codes. When it started there was an uneasy consensus as to what codes meant what problems, and were owned by what module. As development proceeded, though, error codes began to overlap - which led to extra pointless (and non-robust) code to convert between error codes. It also led to a spaghetti of dependencies between modules where no error codes could easily be changed.

A more modern language like Java or Smalltalk which allowed real objects to be returned as an error value without hair-pulling memory management issues might go part way toward solving 3, but at the cost of making programmatic error handling a lot more difficult (parsing error strings, gobs of "instanceof" etc.) but 1 and 2 would still remain.

In the prototype Java replacement system this whole idea was replaced by a _small_ set of exceptions, potentially thrown by everything and caught by default at the top level. The vast majority of code just implemented its correct behaviour, using its return value for something that made sense. Most immediate-action type errors were caught locally and handled, but in a few cases an exception would propagate a level or two. Reading the new code was like a breath of fresh air. The only down sides were adding "throws FSException" to all methods when created, and a silly little "if (never) throw new FSException()" at the lowest level to shut up the compiler.

-- FrankCarver


I don't know it makes sense. You don't need exceptions to use arbitrary objects. Anyway, here's where C3 uses exceptions:

One: The main exception handling in C3, which is only a couple of thousand classes of course, is this: surround payment of an individual with an exception handler. If an exception occurs, write the stack to a file, pay the next guy.

We don't care at the time of pay why he didn't pay, we just have to go on. When we want to know why he excepted, we just pay him again with the handler off and catch it in the debugger.

Anything else would be overkill.

Two: Another place is in deductions where a required deduction (savings typically) raises an out of money signal, sets a flag to turn off certain optional deductions, runs the deductions again. If it works, go with it. If it doesn't, he's dead.

Three: Finally, and I wish this weren't true, there's an exception handler deep in the I/O code. This handler allows the code to retry some obscure thing or other. It also has been known to mask all kinds of errors.

In my opinion, number One is perfect, Two is marginal, and Three is bad.

-- RonJeffries

Pain-in-the-ass code comes in two flavors: code that is too stupid and code that is too smart. Ron's Three is a frighteningly common type of the latter. If you must handle an exception, handle it thoroughly! If you can't handle it thoroughly, don't handle it at all! You'll only obscure the clues you'll need to resolve a real problem.


> Anyway, here's where C3 uses exceptions:

That's where you catch them. You throw them from a great many places. Every object creation will throw if there's not enough heap space, every message send will throw if there's not enough stack space. Every array access will throw if its index is out of range. How many places is that?

If by "use" you truly mean "catch", then maybe we should start this argument again, as AvoidCatchingExceptionsWheneverPossible?. -- DaveHarris

I don't understand. Do you perceive that this page is discussing whether the internal operations of C++ or Smalltalk / Java virtual machines should throw exceptions when out of space? Seems to me that the whole discussion is about throwing exceptions of ones own, which I recommend doing rarely, and catching whatever exceptions are thrown, which I recommend doing in as close to one place as one can get

Sounds like two separate policies to me: one for throwing and one for catching. David's comment does remind one that exceptions are thrown from many locations, often without our consent. That forces us to have an exception catching strategy. You recommend catching them all in one place or as close to a single place as you can. I recommend catching them where operations that throw exceptions are initiated. I get the sense that C3 has only one operation: write paychecks. If that's the case then we're really recommending the same thing. I'd break that down into sub-operations so that I could generate better error messages but you don't appear to need that.

The other policy is when to throw. Since ExceptionsCancelOperations, throw an exception anytime your code can't (or shouldn't) continue with what it's doing. -- PhilGoodwin


There are millions of things that can go wrong with writing a paycheck. We didn't get over 2000 classes because payroll is simple. Imagine my surprise - I thought it was. Two things that can go wrong, NegativeResidual? (guy gets a negative check, implying something computed incorrectly), and Error (system exception such as array out of bounds, missing dictionary key, etc etc) throw exceptions. The first throws an exception because it has to abort shipping the guy his check. The second throws an exception because that's what Smalltalk (and every other language) does when some relatively primitive action goes awry. We handle those centrally, as discussed above.

Everything else, such as improper input, one input without a matching other, bad format, illegal combination of savings options, whatever, are handled by checking the condition, and either filing a "Notification" or going on with the intended operation. Some Notifications are informational and are checked by humans after the run. Some are fatal and put the employee in an unpayable state. These employees we never try to pay until a human has cleared the error.

Every one of these many problems could have been dealt with by throwing an exception (ImproperInput?, UnmatchedInput?, BadFormat?, ...), handling the exceptions in some central place, and redispatching the exception type to generate the message. And then restarting or continuing if the error was sufficiently mild. The code to do it conditionally is the same, and the action is much more clear when written at the place of the test.

In my experience, Exceptions are too deep in the bag of tricks to be used frequently. No operation that unwinds the execution stack to an location unknown can be a good thing to use as a matter of course. It's a shame that some languages force them upon us.

-- RonJeffries

I get the feeling that we, in fact, agree - even though we describe our approaches in opposite terms: I say that I use exceptions "all the time" and that they're a good thing. But I only throw them from low level functions that fail in unexpected ways -- errors from relational database, network, or ZIP compression algorithms being typical. And I handle them at the highest possible level - typically by setting the transaction aside and going to the next one. In fact, I probably would not throw an exception for a negative check: That sounds like a business policy to me. (And checking that deductions have the expected sign would be good too.) -- JeffGrigg


A simple example, perhaps not quite accurate. I have the impression that in Java, things like missing key typically throw exceptions. So you have to handle the exception (and it sounds like the compiler insists that you do so in many cases).

The corresponding thing in Smalltalk works like this:

 aDictionary at: 'someKey'
will throw an exception if 'someKey' is not in aDictionary. However, if this is considered to be possible, one just writes:

 aDictionary
   at: 'someKey'
   ifAbsent: ["do whatever is right if the key is not found"]
This is direct, not an exception, and eminently clear. Or so it seems to me. -- RonJeffries

But if your block causes the method to return, Dictionary>>at:ifAbsent: could be in for a real surprise. The block can cause on-local transfer of control out of any number of methods. Seems to have most of the misfeatures of an exception. -- BT

VisualBasic has the misfeature that you can't check "ifAbsent:". So, it's common to write a function, say "IsInCollection?()" that attempts the fetch, catches the error and returns True or False.

I do it all the time in spite of being "in favor of exceptions." You see, you shouldn't throw exceptions except in exceptional conditions. ;-> -- JeffGrigg


I have been thinking about this some (the hazards of taking a shower), and came to the realization that the argument that the exception is "cleaner" is actually based on a presumption regarding the nature of the problem. Multiplying a matrix is one thing, but take a different problem: "Prompt the user for a file to open until they actually name one that can be opened." This is easiest with error codes:

do {
filename = user.getFilename();
} while ((file = open(filename)) == null);
With exceptions, you have to go through the ugly contortion of creating your own error code (as best as I can tell):

do {
filename = user.getFilename();
try {
file = open(filename);
} catch (FileOpenException? e) {
file = null;
}
} while (file == null);
(Oddly enough, if I understand Eiffel correctly, the opposite is true - retrying is easy, trying once and then providing a default value looks to be ugly)

So, here is what I hope is an even-handed way at looking at the problem: Error codes damage the data stream, exceptions damage the control flow. Which is the less undesirable depends on whether it is easier to repair the data stream or the control flow based on the problem and language involved.

-- BillTrost


The error code style of programming is not a good idea, not only because it corrupts the data stream, but also because it encourages reuse of temporary variables for two unrelated purposes - to hold the intermediate result, and the error code. Many functions return two results: the value you need and the success/failure status. You should deal with them separately. So we get

boolean found = false;
do {
filename = user.getFilename();
try {
file = open(filename);
found = true;
} catch (FileOpenException? e) {
// decent error message here, perhaps
}
} while (!found);
Always use temporaries as write-once single-assignment variables, except for loop indices that are used in a predictable manner. Use temporary names as comments on the intermediate result (Note that this is not possible if you use write-many temps). It initially seems annoying, but down the line makes code much easier to understand and change.


Another way to write this without the temporary variable:

while (true) try {
filename = user.getFilename();
file = open(filename);
break; // task complete without problem, go on
} catch (FileOpenException? e) {
// decent error message here, perhaps
}
I don't know which one is better, I use this form because I don't like to use temporary variables.


In the case above, I'd rather not pretend that finding a file is somehow "normal" and not finding it is exceptional. When it comes to resources, it's best to test explicitly (except ultra-ubiquitous resources like memory, of course)

if (exists(filename) && permissions_ok(filename))
I don't much like the "try catch" syntax for this, or the many cases where java uses exceptions. In MyFavoriteNonExistentLanguage?, I would have functions return two values, success indicators and the result, for many cases where java uses exceptions. And use a one-line ifFail: style syntax to handle the "failure" case. Exceptions that alter control flow would be reserved for really exceptional cases, where you violate preconditions, for example, or where the method violates postconditions due to resource problems, network connections, etc. -- AamodSane

That isn't strictly safe, because of the potential race condition - you can't guarantee that by the time the OS gets around to handling your open() call that the file will still exist and have suitable permissions. Testing a file before opening it can have security consequences, so it should be avoided unless you know that the operation is atomic at the system level.


I come from a CommonLisp background and I don't understand the problems people see with exceptions. There is in general a gap between the place where you detect a problem and you have all the information about the problem and the place where you have enough information about what you are trying to achieve and you have enough information to formulate a strategy on how to handle the problem. Exceptions give you a structured way to transfer information between these points.

Of course, the Common Lisp condition system is more elaborate and powerful than the exception systems discussed here.

I wonder what some of the opponents of exceptions think about the design of stuff like restarts. At http://www.nhplace.com/people/kent/Papers/Exceptional-Situations-1990.html, you can read a nice design paper with link to the real specification.

Culturally, Common Lisp's kitchen sink approach goes against YouArentGonnaNeedIt, I suppose.

-- Lieven <mal@bewoner.dma.be>

Personally, I like exceptions because they allow me to enforce layer separation in a HexagonalArchitecture.

-- Laird <ljnelson@unix.amherst.edu>


No, CommonLisp isn't going against YouArentGonnaNeedIt. The Common Lisp exception facility is a grand refactoring of many, many application programs over the years. (Of course, it's harder to apply the concept of "need it" to a language than to one particular custom software product!)

-- DanWeinreb


It is really pleasure to throw exceptions if you're writing a software component which will be used by others. Of course, you must not be one to catch them (See ThrowDontCatch)

But, if you are on the other side, it is better to catch exceptions locally, and return error codes etc. -- avasAlparslan


The matrix determinant and inverse examples given here are red herrings. Computing the determinant of an n by n matrix is an O(n!) operation, while computing the inverse by row reduction with pivoting tends to be an O(n^3) operation. Typically, one just goes ahead and uses the row-reduction algorithm. If the algorithm gets stuck, it's because the matrix is singular (or very ill-conditioned). In that case, the algorithm must either report an error code or it must throw an exception. I'd prefer the exception.

Besides, the examples compared the determinant to 0.0, which is a bad idea. Floating-point arithmetic is fuzzy; don't test floats for equality. -- EricJablow

Computing the determinant of a matrix is no more O(n!) than inverting it. Just triangularize and then the determinant is the product of the diagonal elements. Time is O(n^3).

Oops. D'oh! On the other hand, testing the determinant and then doing the inversion wastes a lot of effort anyway. Also, testing the determinant does not help with ill-conditioned matrices. If the ratio of largest eigenvalue to smallest eigenvalue is 10^10 or so, you may need to treat the matrix as singular anyway. Or you might not. Consider the diagonal matrix with diagonal [1, 10^10]. Then, consider the Hilbert matrices H_n given by h_{ij} = 1/(i+j), 1 <= i,j <= n. The first is ill-conditioned but easy, the second is ill-conditioned and hard. -- EricJablow


I wonder if there is a term for the following pattern:

"worker" functions are written which, according to their unit tests, perform acceptably if given inputs within valid ranges. "buffer" functions wrap the worker functions, validate parameters, return error messages or throw exceptions if parameters are missing or invalid, and only call the underlying "worker" functions if parameters are valid.

"Bad programming I don't do because I know C better than you do" is not a useful name for this pattern, by the way.

-- ChrisBaugh


I hereby banish this into the CategoryAntiPattern.

The reason is that I believe many people will take this as an excuse to do code like:

try { doSomethingInSql } catch (SqlException? e) { SomeLogfileThatIsRedirectedToDevNull?.write(e.getMessage()); }

The next reason is that this encourages C style code, where a part of the domain of the return value is reserved for error codes, for example, to return -1 if an error occurs. However, C programmers can't seem to agree whether 0 signals an error, or values less than 0 do. The problem actually is that the programming language doesn't easily allow the return of tuple results, so the advice "AvoidExceptionWheneverPossible?" will work, but only in a language that encourage the use of tuples, like PerlLanguage.

Maybe advice like "Use Errors instead of Exceptions" and "Don't hide errors." would be good.

-- PeterSchaefer

See OutOfBandChannel for another perspective.


After working with error codes, boolean return values (the absolute worst), and exceptions (in various languages), I believe exceptions are, in general, the better way to handle truly erroneous conditions. There is a time and place for all of these means of indicating errors. However, I believe that, for most programmers (all but the most experienced), exceptions are the best error handling mechanism.

The main reason is this: If you don't explicitly handle an exception, Something Bad Happens, and that is a Good Thing. Consider the consumer and producer of some facility - in the simplest case, one method calling another. If the consumer is written by a conscientious programmer, then s/he will check the return value / catch the exception (or knowingly allow the exception to bubble higher). In this case, the overall system works well, no matter if the facility producer (the method called) throws an exception / returns an error condition or not.

However, if the caller is written sloppily, or quickly, it is unlikely that the caller will check the return value / catch the exception (when appropriate). If you use return values, the error is simply lost, and the internal logical consistency of your system has just been - silently! - destroyed. Your system may continue to do something useful, but most likely, it will fail in a subtle, hard-to-diagnose fashion. This is all too common in the very real world. But if you use exception handling, then at least Something Meaningful happens in this circumstance - an exception bubbles to a very high level (perhaps to the runtime environment itself, if the application does not handle the exception). This is the better outcome, because you have all of the information you need to diagnose the problem - you know exactly which method failed, and why, and when. It is then up to you to decide how to handle the error - but you have already done the hard part, in locating the source of the problem.

Also, the collective authors of this article have largely ignored a very useful aspect of exceptions (in some environments) - exception chaining. Some environments allow you to indicate what the "root cause" of an exception was - a reference to another exception. (In MS CLI, this is the InnerException? property.) Thus, if a lower-layer driver indicates that a write to a disk failed because the disk is full, the database application can wrap the DiskFullException? in a DatabaseCreationException?, etc. This gives you an extraordinarily useful description of not only the fact that an error occurred, but what damage that error caused - for loss of a nail, the horse was lost, etc.

I've found that many (possibly even most) of the articles on this Wiki that I have read, have been very close to my own experience in professional software development. However, I'm very surprised to see so many people weigh in against exceptions. When used consistently, I've found exceptions to be a very powerful, natural, and simplifying aspect of modern programming languages.

Also, a further note. The writer at the start of this article states that exceptions make "debugging a nightmare". I think that is exactly backward. Modern debugging environments make it possible to see all of the details of an exception that has been thrown, including the exception properties / fields, stack trace, and all of the usual debugging you expect from normal procedural debugging. Many debugging environments allow you to set first-chance/second-chance breakpoints on exceptions, so that you can examine program state when an exception (of a particular type (including derived types)) is thrown. This is far superior to error codes.

Exceptions emphatically do not complicate code. Empirically, looking at very large code bases that I have worked on (specifically components of Windows NT), comparing code that consistently makes use of exceptions vs. code that consistently makes use of error codes, the exception-based code is significantly more concise. This isn't a belief, but an empirical observation, derived from many large, mature projects that I have worked on.

And exceptions do not complicate "thinking". They simplify it. Compare these two methods and their invocations:

ERROR_T CheckSomeCondition? (
bool * ReturnValue?);
...

ERROR_T Error;
bool ReturnValue?;
Error = CheckSomeCondition? (&ReturnValue?);
if (Error != ERROR_SUCCESS) {
...
}
if (ReturnValue?) {
real work;
}
else {
other real work;
}
vs

bool CheckSomeCondition? ();
...

if (CheckSomeCondition? ()) {
real work;
}
else {
other real work;
}
On a line-by-line basis, exceptions definitely make code more concise - the code is far closer to SelfDocumentingCode. And typically, you use a single try/catch block to handle exceptions from a moderately-long sequence of instructions.

So, obviously, I strongly disagree with the original author. An exception is NOT a goto - it is a data-driven (and detailed) description of an error condition that an algorithm has detected. Exceptions are a clean separation of the description of the error condition from the processing of the error condition.

-- ArlieDavis


I find that exceptions are a clear win when error handling is complex and deep. When it's simple (as it usually is in the examples people show to each other) then the benefits are non-obvious. There's still some benefit - it can be more performant, for example, and there's a benefit to consistency even if an exception isn't an obvious need in a specific case. An example from my experience where I would have liked to use exceptions: I was writing a wrapper class around some DirectShow components for simple movie playing. DirectShow is a very complicated library and the initialization of the object created 6 DirectShow objects and called about 2 dozen methods. Every single one of these calls needed to be checked for an error value and appropriate action taken - in some cases it could be ignored, it some an alternate code path had to be taken, and in most cases I simply had to fail. The error handling code more than tripled the size of the function - there was hardly any "meat" involved, 2 out of every 3 lines were checks against return values. It was messy and ugly and terrible. Returning error codes to the caller was another mass of annoyance, because this was library code and clients of my library shouldn't have a dependency on the DirectX headers. So I needed to convert all the DX error codes into my own versions of them, in place everywhere they existed, and then return those up to the caller, who of course would have to figure out what to do with them. All in all a terrible situation. A lot of the programmers I know who advocate against exceptions would have simply ignored or not propagated most of the error codes, and just crashed (hopefully by logging a fatal error rather than hard crashing) instead. Exceptions provide an elegant way around this situation, by simplifying code flow in complicated cases, and by only requiring work by someone who cares about the error condition. In the error value case, every author and every caller at every level has to maintain discipline about checking and propagating error codes so that the top-level caller can take correct behavior. An exception can written OnceAndOnlyOnce and then caught by whoever wants to handle it.


A lot depends on what you choose to call an error and what you choose to call an exception. End of file on input is neither; I use AdamsLaw as the distinguishing principle. If it can happen on a system with nothing broken - it's an error. If it's something that can never happen, it's an exception.

An error should be handled by the code that triggered it and not passed "up the stack". Assuming competent design, the error I see is not the error my caller should see if I can't swallow it. If I've timed out communicating with some host, the error I get might be a lost ack; the error I pass on is host unreachable. My caller might pass on a service inaccessible error or access an alternate server with the upstream code none the wiser.

An exception is a different class of thing - it is totally unexpected and signals the type of failure that says I can't continue. It needs to be sent up the stack until it finds code that knows what to do. Only the code that knows what to do should catch an exception. This is reserved for things like running out of memory.

Also, passing an error or catching and then throwing an exception up the stack without adding information to it should be grounds for serious public humiliation. -- MarcThibault


To me, the problem seems to be solved by a well-designed exception hierarchy (including some serious abuse of interfaces/MI). If that exists, then you can have every behaviour that doesn't return the exact expected type be handled by exceptions. Java had a good idea in that some exceptions didn't have to be in the exception spec (but unfortunately, did have to be caught if there was any other "try/catch" going on). C#'s debugger can catch an instance of any creation of any exceptions. I'd go so far as to say that, with a really really good exception class tree, you could use exceptions for things like

string.indexOf(char c) throws CharNotFound?.

After all, is

 int i = foo.indexOf(c)
 if(i < 0) 
   dofail()
 else 
   dosucceed(i)
any simpler than

 int i;
 try 
   i = foo.indexOf(c)
   dosucceed(i)
 except CharNotFound?
   dofail()
really, the only nuisance is the predeclaration of "i". The fact is that for some reason coders just "like" the "if/else" block better than the "try/catch" block.

There are tons of alternate syntaxes available. Personally, I'd like to see an optional alternate syntax for "try catch" that avoids the scope problems of try/catch called "=try". "=try" works like a normal try except that (a) it's a one-line try block, (b) the "try" part takes place in normal scope and assigns the return value of it's contained statement, and (c) all "catch" blocks _must_ return or throw. Either way though, fundamentally -1 is _not_ and index. If you try to use it as an index, things will blow up. It is an exception to the index.

The fact that languages have primitive, cumbersome scoping syntax for doing exceptions doesn't mean that exceptions aren't the right way to handle _all_ returning data that isn't of the exact type expected.

Alternate thought: exception specifications were a good idea - exceptions are part of the function signature. The problem is that they're also a pain to handle. They should be implied type info, and unhandled exceptions are _not_ an error (unless this function is implementing an interface that defines a far more limited set of exceptions).

After all, if (a) throws boo, and b throws bar and calls (a) without handling foo, then we obviously know that (b) throws foo or bar. No need to clutter up the function declaration with that info - put it in the module headers, the tooltips, and the autodocs. And just include a class of "system exceptions" for things that nobody would ever know to handle that are implicitly in every function interface.

Of course, a language with good blocks syntax could dodge most of the syntax pain by simply having the exception be part of the function signature as a block that must be passed in.

 i = myString.indexOf(c, charNotFoundHandler = {dostuff()} characterSetIncompatibleHandler = {throw e})

To ignore the exceptions, simply provide an empty handler. The difference from normal exceptions is that in this model, indexOf must return _something_ if "charNotFoundHandler" or "characterSetExceptionHandler" do not throw or return. Thus, we get the best of both worlds. It can be used like an exception, or it can be used like an odd return object. The "throwing" syntax is nice too, simply stating "return charNotFoundHandler(new charNotFoundException())" - if an exception is to be thrown, the handler will do that.

On the other hand, such an approach would make my previous suggestion of exception specification type inferencing a colossal pain in the ass.

-- MartinZarate

See also: SeparateIoFromCalculation


CategoryException


EditText of this page (last edited January 17, 2014) or FindPage with title or text search