Okay, this is all about exceptions... as in try/catch. This is not a technical post, but a subject that I have pretty strong feelings on. Please let me know if you disagree -- It may be hard to change my mind, but I'm glad that people still try.
Here's the meat: I'm really sick of seeing and hearing people claim that exceptions are for exceptional cases. I'm equally sick of people claiming that exceptions are for errors. I believe strongly that neither is the case. What an exception means is that something happened inside a section of code that was assumed would not happen. While this may mean something like an error reading from disk, it may also mean something so basic as an implicit contract between function caller and callee was broken.
Okay, so let's get to the examples. Let's say that I am writing a function - it takes a string representing a number in the Fibonacci series. The function returns an integer specifying what position in the sequence that number represents.
(For those who don't know the Fibonacci series, it starts off 0,1,1,2,3,5,8,13... each number in the series after the second is produced by adding the two numbers before it. So the next one above is 8+13 = 21)
Now, what do I do if the string passed in is not an integer, or isn't in the series? Let's take it as a given that I throw an exception (we can argue that point later). Why do I do that? Is it because
- It's an error?
- Or, because that case is "exceptional"?
Do you have an answer? If you do, how did you come up with that answer without knowing how the function will be used in an application?
The developer using this function may parse user input, pass each string token in, and if it is a number in the Fibonacci sequence, perform some special action. If an exception is thrown, the user is prompted again. So in this case, it's not an error to pass in "hello". In fact, that case is being expected and handled. So in this case, it's not an error. It's not exceptional (it may happen that 15 or 24 are passed in more often than passing in an integer in the series).
So the right answer is "neither". In fact, we often don't know how our function will be used - so labeling exceptions as "for exceptional circumstances" or "for errors" is misleading… and following either as a guideline or standard will cause many problems.
Instead, we simply use an exception to enforce our contract (pass in a string containing an integer in the Fibonacci sequence). We'll use the compiler to enforce as many aspects of the contract as we can -- the "pass in a string" is enforced by the compiler -- and use exceptions to enforce the ones the compiler can't.
Okay, so I skimmed the surface… In fact, I try design code so I don't have to throw for situations that can be expected to occur (I may change from "string" to "int" params in the sample above or even completely revamp design of the API). But please don't say "only throw exceptions for errors", or "only throw exceptions in exceptional circumstances" without thinking about this first.