How to handle un-exceptional errors

C

clintonb

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?

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.

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
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.

- Clint
 
C

clintonb

I also wanted to mention that the Microsoft documents I read (in
particular "Best Practices for Handling Exceptions) don't really show
examples of handling unexceptional errors. They just show examples of
trying to prevent exceptions from being thrown in the first place.
Before calling some code that may throw an exception, they just check
for likely error conditions before calling the code.

I was curious how some of you would handle this example. One example I
read about in a Microsoft document was the situation of logging into an
application. A user is likely to enter a wrong name or password. So
this is not an exceptional situation. So how should we handle such an
unexceptional error?

If I were writing a program, I'd have a GUI layer and a business logic
layer. The GUI layer would have a login form that would call a Login()
method of some class in the business logic layer. The Login() method
would contain the logic to determine if the user entered a wrong name
or password.

But how would my Login() method in the business layer pass that message
back up to the GUI layer? In the past, I simply threw an exception
that the GUI would catch and handle.

I suppose, I could return an error code instead and have the GUI handle
it. Perhaps one error code would represent a bad name, the other a bad
password.

That's not so bad since I only have two layers in my call stack. But
what if I had a situation where one piece of code calls another piece
of code which in turn calls another piece of code. It would be nice to
know the whole call stack trace for diagnostic purposes. It would also
be nice to perhaps display a more user-friendly message at the GUI
layer. Exceptions have all that functionality. How would you handle
this if you weren't using exceptions.

- Clint
 
T

Tasos Vogiatzoglou

In general I prefer to use exceptions only for exceptional errors :) I
like to distinguish the semantics between a system exception and
user-raised errors and let this distinction be visible in the code. I
find exceptions to be too expensive to raise and handle.

Martin Fowler has written a nice article about the Notification pattern
(http://www.martinfowler.com/eaaDev/Notification.html) that can be used
in such cases.

Regards,
Tasos
 
H

Helge Jensen

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top