When a method fails, should it throw an exception or return a value that indicates an error? That was the subject of a lively discussion at work this week.
We decided to settle the dispute by deferring to the excellent book, Framework Design Guidelines, by Krzysztof Cwalina and Brad Abrams. They came down solidly on the side of exceptions and I thought I’d paraphrase some of their reasons in this post.
Consistency. You don’t have the option of returning an error value from constructors, operator overloads and, in some cases, properties. Exceptions are your only choice. If you want to be consistent, then, you must use exceptions everywhere.
Single Responsibility Principle. An exception is used to report failures and nothing else. Why burden a return value with that additional responsibility when it is already doing other work?
Flexibility. A return value must be handled when it is returned. You can catch an exception as far up the call stack as you wish.
Consolidation. With return-value-based error-checking, you must write an if statement to check each return value. If you’re using exceptions, you can consolidate all the error-handling in one try/catch block if appropriate.
Safety. If you fail to catch an exception, the results will generally be much more noticeable than if you don’t check a return value. As ugly as an unhandled exception is, to proceed naively after a failure can be much worse. And you can always install a graceful exception handler at the top of the program as a catch-all.
Richness. An exception can generally carry much more information than a return value. (When was the last time you saw a return value that included a stack trace?)
The next question was, when should you throw an exception? The book’s answer was simple:
If a member cannot successfully do what it is designed to do, it should be considered an execution failure, and an exception should be thrown.
Or, as Jason Clark commented,
A good rule of thumb is that if a method does not do what its name suggests, it should be considered a method-level failure, resulting in an exception.
That all makes sense to me. What do you think?