Some programmers, and even Microsoft documents, say you should only
throw exceptions for exceptional situations. So how are others
handling all the other unexceptional errors? How are you propagating
errors up the call stack?
The theoretic, and to to extent real-world objection is "What is
unexpected for some is common-place for others".
The whole "only-throw-when-unexpected"-church has limited value, the
implementation code selects whether to throw or not, the caller knows
what is expected. The two do not necessarily agree on what is to be
expected.
Take File.Open, for an example. It fails by exception, but is it really
unexpected that an open with FileMode.CreateNew may fail? You can argue
back and forth about this, but the bottom line is, it's not really
well-defined. In C# however, it throws an exception.
In the past, in my C++ code, I used to throw exceptions for ALL errors,
exceptional or not. It seemed like a nice clean method for detecting,
handling, and propagating errors. You can find multitudes of articles
on the internet that argue that using exceptions for error handling is
the only way to go. With .NET I'm even more inclined to use exceptions
because they are rich in useful features.
Exceptions have some problems:
1. Exceptions require special treatment even in code not "otherwise
concerned" with the exception.
Code needs to be "exception-safe", that is, cleanup need to be
taken serious in the face of exceptions.
It's not that much of a problem anymore, since exceptions may occur
essentially everywhere in polymorphic-programming anyway since you don't
know what you may be invoking. It still is a problem for code that need
to be transactional though.
2. Exceptions are (essentially) non-local returns
The control-flow can get pretty hard to decipher, and reading the
code can get pretty hard with try{...} catch { ...} all over the place.
3. Exceptions are not first class language-constructs
It's hard to write code that conditionally catches an exception.
try {
...;
} catch ( ... } {
if ( canhandle )
...;
else
throw;
}
is really nothing more that an ugly workaround.
4. Catch-by-type vs. nested-exceptions:
(in C#1 at least) catching an exception by type will "fail" in
places where the called method "wraps" exceptions, most notably when
invoking code whose implementation is a delegate:
public void g() { throw new FooException(); }
public void f() {
// Made-up example for brevity
ThreadStart t = new ThreadStart(g);
t();
}
public void h() {
try {
g();
} catch (FooException e) {
// Ups, never caught, you must:
} catch (Exception e) {
for ( Exception inner = e; inner != null; inner = inner.Inner )
if ( inner is FooException )
// handle
}
5. "Grouping catch"
People tend to "group" catches:
try {
f();
g();
h();
} catch ( ExceptionFromF ) {
...;
} catch ( ExceptionFromGOrH ) {
...;
}
but often "ExceptionFromF" may be throw by g() or h() without the
caller knowing. This is related to the next topic:
6. try...catch introduces scope
you can't declare locals where they are defined:
try {
Stream s = f();
} catch ( ... ) {
...;
}
s.Write(...);
you must declare them before the definition:
Stream s;
try {
s = f();
} catch ( ... ) {
...;
}
s.Write(...);
or do "grouping catch":
try {
Stream s = f();
s.Write(...);
} catch ( ... ) {
...;
}
But, exceptions is a nice way to make the error-less path of a program
easy to read. The problem is, often the error-recovery/handling path is
just as big
So what is the downside of using exceptions to handle all errors? It
seems like the only downside I've read about is the overhead of using
If performance is the only issue you're worried about, take it easy.
Unless you throw 100s, maybe 1000s of exceptions per second.
Another thing, which isn't *really* a language argument, is that you can
set the debugger to break when an exception is thrown and be stopped at
the location of the erroneous code. It's really nifty when debugging
loops. It works a lot better if you only throw when something is "really
wrong".
exceptions. In my C++ code, I never noticed any significant
performance hit in my applications (which are simple database
applications). Is this worse in .NET? The only other arguments I've
seen against using exceptions for non-exceptional errors seem like
"religous" arguments.
*Pragmatic* religion is fine by me..., it's good to have some "rules"
that you think about before breaking -- it's even better if you know why
the rules are there
I prefer to throw when (one of):
- I cannot return a valid value
- The code cannot complete what it promised
- Ignoring the return-value is a common and often vital mistake (LogOn
- Errors are too complicated to be enumerated (no ENUM,) or have
explanations (login failed because ...) and therefor need to be objects.
I prefer to return bool/error-codes when:
- The error reason can be precisely determined from the bool/error-code.
- I expect high-performance demands, for example for data-structures
- Communicating through a protocol, often with an added text-message
- mirroring API from non-exception-able languages (you can always add
a layer which reformulates the API using exceptions)
It is nice if using a protocol of bool/error-codes is clearly visible in
names used. For example "bool TryPerformX()" instead of "bool PerformX()".
There certainly are places where I *use* and *like* non-throwing,
bool-returning functions, for example IDictionary.TryGetValue,
{int,bool,...}.TryParse when combining expressions depending
conditionally on the value of an exsisting entry or the parsed value --
if successful.