Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Whether error handling by throwing exceptions is good or bad is contentious.

Are exceptions as control flow considered a serious antipattern? If so, Why?

The common line is that exceptions are for "exceptional circumstances". But what if a library author has decided to throw an exception? The library author cannot predict what might be an "exceptional circumstance" for us.

Of course, if we cannot rule out an exception being thrown from a function that we must use as-is and permitting the exception to bubbling up to the top is unacceptable then we must catch the exception.

Often however, we can take preventative measures. With sufficient effort we might even be able to guarantee that the conditions under which the library function would throw an exception will never occur. The throw will still be there (it's not our choice) but we can eliminate the need for try and catch.

An example is std::map.at(). (Pretend there's no std::map.find().)

What is the general wisdom? Is it in good taste to write code with the expectation that a library function will occasionally throw? Is client code obligated to minimize the use of exceptions?

Edit To try and distinguish this more from past questions and be more concrete, suppose we have some library function that might throw a file not found exception. Some client code wants to use the library to access a file. The client code is being programmed with the expectation that the file sometimes will not exist, even under "unexceptional circumstances". The client code can be made able to check if the library function will throw an exception before being called but it's non-trivial to do so. Should client code pile additional error checking on top of the error checking within the library or should the client code use the library generated exception as control flow?

In such a case adding error handling code on top of the library will almost certainly be less efficient than catching an error, will require less coding, and it could be argued that you must have a try/catch anyway. On the other hand it is a decidedly unexceptional control flow mechanism.

share|improve this question
1  
Isn't this 'done to death' on the web? In the question you linked to, there is an answer which summarises the issues described at c2.com/cgi/wiki?DontUseExceptionsForFlowControl. So I don't understand the nuance that you might be asking that hasn't already been answered. Can you give a 'unlike those questions and answers, I am asking ...' to help me understand? –  gbulmer Aug 14 at 21:34
    
The difference is that the exception already exists and is for whatever reason set in stone. Should client code be responsible to avoid incurring exceptions? The other questions I can find regard whether or not the exception should have been put there in the first place. –  Praxeolitic Aug 14 at 21:44
2  
see: How should I handle exception that *should* never be thrown? "let the application crash. If that ever happens, then you know that something is deeply wrong... It is best to not handle an exception if you cannot handle it intelligently..." –  gnat Aug 14 at 21:44
1  
Huh? If you didn't want an unhandled exception you probably don't want to immediately abort either. –  Praxeolitic Aug 14 at 21:52
1  

5 Answers 5

The common line is that exceptions are for "exceptional circumstances".

Well, it's wrong.

Catching is certainly something you might want to do rarely, but exception throwing is not for exceptional circumstances at all. You should throw whenever a run-time condition means that you cannot fulfill your contract.

There's a big middle ground between "Using exceptions to replace if" and "Exceptions are only for exceptional circumstances".

Oh, and contracts that mean "Every caller must check for error every time", like return codes, are vastly worse than "Using exceptions to replace if".

share|improve this answer
4  
Code not being able to fulfill its contract is an exceptional circumstance. –  DougM Aug 14 at 22:20
1  
It's perfectly non-exceptional to imagine that a file might not exist. –  DeadMG Aug 14 at 22:21
3  
you're using a weird definition of "exceptional." The word is closer to "unusual" than "unimaginable." –  DougM Aug 15 at 0:35
    
I have always understood "exceptional circumstances" to mean "circumstances that are unlikely to occur if a normal user uses the system in a normal way, but that can occur anyway if the system is used in unusual circumstances or if unexpected interactions with external systems occur." Trying to work with a file that doesn't exist counts as an unusual way to work with a system in my book unless you wanted to create that file. –  Bart van Ingen Schenau Aug 15 at 7:08
    
@BartvanIngenSchenau: Seems perfectly reasonable to me that the user made a mistake and tried to work with a file that he thought he created but got put in the wrong directory or he accidentally deleted or something. –  DeadMG Aug 15 at 9:28

Handle exceptions you can handle and let others bubble to the top.

When a library-function throws a FileNotFound exception and you have a way to gently handle that exception. Do so, but the same function might also throw a IAmGoingToCorruptYourMemoryInEvilWays exception which you can't handle then you let it bubble to the top.

The common line is that exceptions are for "exceptional circumstances". But what if a library author has decided to throw an exception? The library author cannot predict what might be an "exceptional circumstance" for us.

In my opinion you should read it as exceptional circumstances within a system. And for the library function the system is small and the act of trying to read a file that isn't there is exceptional. In the larger system where the library function is used, the file not being there may very well be something that's to be expected, so you deal with the FileNotFound exception in that system.

share|improve this answer

To me it's all a matter of abstraction layer consistency: if you throw something you catch yourself in the same context you are probably abusing. If you are throwing because of something you -at your actual level- don't know how to handle, throwing is the right way to go.

Who called you probably known WHY did he called, and hence knows also what to do if something goes wrong.

Now, about the catch: the correct place to catch is the one at with the reason for the error can be understood and the problem can gently be solved.

Suppose you are writing a function to manipulate a file: if the file is not there or if you find it is not in the expected format, since it was not you who supplied the file, you cannot know why it happened. So, instead to attempt a workaround yourself (that can be not what your caller intended) just throw reporting the problem.

Suppose you are he one that calls a function that has to manipulate a file: if that was you who gets the name of the file from the user, and the file is found as being not there or not being as expected, you should catch and ask again and eventually admitting an answer like "do nothing and let me go". If the name of the file was instead already given to you from somewhere upside, you should let the exception go up.

Another typical case is a function requiring a container to grow. If the memory allocation fails, the allocator will throw. The container- at that point- has to react to put itself in consistent state (no dangling pointers or half-made internal structures), but has to re-throw since it cannot solve the problem of the missing memory.

The catch should probably happen in a place when some other memory can be dismissed (an the operation re-attempted), or the user be informed of the problem to give it a chance to gain more memory for the actual task (for example by closing some other task or application) and reattempt the failed command.

share|improve this answer

What is the general wisdom? Is it in good taste to write code with the expectation that a library function will occasionally throw?

I think you do not understand how the exceptions are used.

What is important to understand is : you can not ignore exceptions. In a normal program execution, an exception must not occur.

If it must not occur, then why use exceptions?

  1. to catch a bug - someone implemented something, that collides with other part of the software. Maybe set a constant wrongly.
  2. to catch invalid parameters - if the user enters wrong value, which is not checked, what do you do? Maybe something out of range, or string instead of a number.

In such a case adding error handling code on top of the library will almost certainly be less efficient than catching an error, will require less coding, and it could be argued that you must have a try/catch anyway.

Again, proves that it comes from a person not knowing what exceptions are.

Exceptions are thrown at places where the error occurs, and caught at places where you know how to deal with the error. This separates the program execution into two :

  • normal execution path
  • error propagation path - when an error happens

This way you can concentrate on the normal execution of the program, ignoring the error path. When an error happens, throw an exception, and move on.

Since, you do not need to check error code, your program will be smaller, more efficient, and easier to maintain and unit test. Last two items are specially good for developers.

Performance wise, program with the use of exceptions will be better or same then the program without exceptions, because of zero-cost mechanism. Only thing that is paid, is a bit increase in the program/library size increase.

Of course, throwing an exception is expensive, but it doesn't really matter. If the program can not continue, then it doesn't matter how long it takes to resolve the error. On the other hand, with error codes, you pay for every check.

share|improve this answer

Java went much further and made Exceptions part of the method contract and, IMHO, that's good. It focuses your thinking about exceptions. When you call a method, you know exactly which exception(s) it might throw, because the method tells you what they are and the Java compiler insists that you deal with them - catch them and handle them, or change your method contract, declaring that "you" might throw these exceptions to your callers.

Because it doesn't explicitly do this, .Net has encouraged a lot of lazy, woolly thinking about exceptions, leading to all of the confusion already mentioned by others.

A method should throw an exception when it's asked to do something it can't.
Defensive programming can only give you so much protection - you can "pre-test" conditions as much as you like, but eventually you just have to call "that method" and you can still get "strange things" happening (system exceptions, race conditions, etc., etc.) between your last check and actually trying to do the work.

You should only catch an exception when your code can do something useful about it. Far too many Developers "finish" their programs and then ask about "Global" exception handlers - catching and logging the [whole!] exception to a file just before the application curls up and dies. OK, it's a backstop, but it's only "useful" up to a point. Catching that FileNotFoundException and trying to read a different file, all without the user knowing it's happened, is perhaps a little more "useful".

share|improve this answer
    
I prefer the .NET approach. When programming in Java, I found that my code ended up with hundreds of empty catch blocks, either because I knew that that exception will not occur, or because the documentation (not only external libs, but the Java class library too) gave absolutely no information on what that exception means. There are just too many places in official javadocs where you can read "This method throws an IOException if any IO errors occur". Thanks, very helpful. –  marczellm Aug 15 at 16:38
    
Java checked exceptions missed one out of two awesome things about exceptions. Java started with checked exceptions and introduced unchecked, and this is now generally favored in most situations. Exceptions are awesome partly because mid level functions don't have to deal with them. Say f1() calls f2()... calls f20(), which is asked to open a file that doesn't exist. f2 through f19 can't do anything intelligent with this exception, so they ignore it. f1() can do a try catch to deal with it. This saves a crapload of cruft in your code... cruft that will be there if you use checked exceptions. –  Nir Friedman Aug 16 at 8:11

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.