Error handling idioms

J

jeffc226

I'm interested in an idiom for handling errors in functions without
using traditional nested ifs, because I think that can be very awkward
and difficult to maintain, when the number of error checks gets about
3 or so. It also gets very awkward in nested loops, where you want to
check for normal loop processing in the loop condition, not errors.
Yes, you could put some generic exit flag in the loop condition, but
when you're simply done if you find an error, it's much more
straightforward to simply leave all of it.

Exceptions would work, but that is inconsistent with the principle
that exceptions be used for exceptional cases, i.e. errors that you
don't expect could occur.

Basically what I have in mind is something using multiple return
points from a function and possibly gotos (both inconsistent with
traditional structured programming).

This seems good to me - thoughts? Further links for reading?

bool f()
{
if (error condition)
goto ERROR_RETURN;

// do stuff

for ...
{
for ...
{
// do stuff
if (error condition)
goto ERROR_RETURN;
}
}
if (error condition)
goto ERROR_RETURN;

return true;

ERROR_RETURN:
// do some cleanup
return false;
}
 
A

Alf P. Steinbach

* (e-mail address removed):
I'm interested in an idiom for handling errors in functions without
using traditional nested ifs, because I think that can be very awkward
and difficult to maintain, when the number of error checks gets about
3 or so. It also gets very awkward in nested loops, where you want to
check for normal loop processing in the loop condition, not errors.
Yes, you could put some generic exit flag in the loop condition, but
when you're simply done if you find an error, it's much more
straightforward to simply leave all of it.

Exceptions would work, but that is inconsistent with the principle
that exceptions be used for exceptional cases, i.e. errors that you
don't expect could occur.

Don't let silly principles get in the way of practicality.

Basically what I have in mind is something using multiple return
points from a function and possibly gotos (both inconsistent with
traditional structured programming).

Single-entry-multiple-exit (SEME) is advocated by many C++ experts,
including Andrei Alexandrescu.

Some people (e.g. me) have argued to the contrary.

But that's just to flesh out possible shortcomings; don't let silly
principles get in the way of practicality.


This seems good to me - thoughts?

The below code is absolutely ungood: it's not exception safe.

Use C++ destructors for cleanup (called RAII).

Then just use 'return' to return.

Further links for reading?

Look up Petru Marginean and Andrei Alexandrescu's scope guard article.
 
J

jeffc226

The below code is absolutely ungood: it's not exception safe.

Use C++ destructors for cleanup (called RAII).

Well that is a good point. My actual code was enclosed in try/catch
blocks, which I left out from the example. I am reading up on RAII
etc., thanks.
 
G

Gavin Deane

I'm interested in an idiom for handling errors in functions without
using traditional nested ifs, because I think that can be very awkward
and difficult to maintain, when the number of error checks gets about
3 or so. It also gets very awkward in nested loops, where you want to
check for normal loop processing in the loop condition, not errors.
Yes, you could put some generic exit flag in the loop condition, but
when you're simply done if you find an error, it's much more
straightforward to simply leave all of it.

Exceptions would work, but that is inconsistent with the principle
that exceptions be used for exceptional cases, i.e. errors that you
don't expect could occur.

What??? That's a ludicrous principle. What is an "error you don't
expect could occur"? If you don't expect a situation to occur why are
you worrying about writing code to handle it? I know that principle
pops up from time to time but I've never yet found anyone who can
explain what it means.

The benefit of exceptions in C++ is that they allow you to cleanly
separate error handling code from the rest of your code.
Basically what I have in mind is something using multiple return
points from a function and possibly gotos (both inconsistent with
traditional structured programming).

Multiple return points - maybe. After all, as soon as expections are a
possibility, single entry-multiple exit is a given. Gotos - not needed
in the way you are using them.
This seems good to me - thoughts? Further links for reading?

Doesn't look good to me.
bool f()
{
if (error condition)
goto ERROR_RETURN;

Just return false here. Failed precoditions are a perfectly acceptable
case for multiple return points. Unless, of course, the preconditions
are entirely under the control of the programmer (e.g. don't depend on
user input) in which case a failed precondition is simply a bug, so an
assert might be more appropriate.
// do stuff

for ...
{
for ...
{
// do stuff
if (error condition)
goto ERROR_RETURN;
}
}

If the loop does not neceesarily run for the number of iterations
implied by the for statement, it looks more like a while loop than a
for loop to me.
if (error condition)
goto ERROR_RETURN;

return true;

ERROR_RETURN:
// do some cleanup

"do some cleanup" should NEVER be necessary. All resources that need
cleaning up should be owned by RAII objects which will do the cleaning
up automatically regardless of how and when the function exits.
return false;

Gavin Deane
 
J

jeffc226

What??? That's a ludicrous principle. What is an "error you don't
expect could occur"? If you don't expect a situation to occur why are
you worrying about writing code to handle it?

This is like saying "If you didn't expect to get stabbed while walking
down the street, then why does the hospital need an emergency room?
An exception is essentially an emergency.
I know that principle
pops up from time to time but I've never yet found anyone who can
explain what it means.

The definition of an emergency is something that we know might occur
but can't be predicted. According to Webster "an unforeseen
combination of circumstances".
The benefit of exceptions in C++ is that they allow you to cleanly
separate error handling code from the rest of your code.

I really don't think using exceptions for all error cases is a very
good idea. If someone logs in and enters a bad password, you are
going to throw an exception? That is hardly "unforeseen". We can
debate endlessly about what might be "foreseen" and what might not be
"foreseen". We typically write a boolean function (that returns a
boolean value.) Such a function should not be replaced by a void
function that throws an exception, IMO. Multiple ways work, and
exceptions can be made to work for all error checking, but this was
not the point of my post.
"do some cleanup" should NEVER be necessary. All resources that need
cleaning up should be owned by RAII objects which will do the cleaning
up automatically regardless of how and when the function exits.

That sounds like an awful lot of overhead for some very simple
things. I am reading an article by Alexandrescu, mentioned in a
previous post in this thread. I think I would tend to agree with his
point: "This approach works just fine, but in the real world, it turns
out not to be that neat. You must write a bunch of little classes to
support this idiom. Extra classes mean extra code to write,
intellectual overhead, and additional entries to your class browser.
Moreover, it turns out there are lots of places where you must deal
with exception safety. Let's face it, adding a new class every so
often just for undoing an arbitrary operation in its destructor is not
the most productive."
 
D

Dennis Jones

On Mar 2, 10:24 am, "Gavin Deane" <[email protected]> wrote:

I'm hardly an expert, but here's my 2 cents worth...

I really don't think using exceptions for all error cases is a very
good idea. If someone logs in and enters a bad password, you are
going to throw an exception? That is hardly "unforeseen". We can
debate endlessly about what might be "foreseen" and what might not be
"foreseen". We typically write a boolean function (that returns a
boolean value.)

Agreed...that's an "expected error" which must be handled appropriately.
There are plenty of these kinds of conditions in which throwing an exception
would be inapprorpriate, particularly since you would have catch the
exception to handle it anyway, which is no different than checking an error
value (just slower).

Such a function should not be replaced by a void
function that throws an exception, IMO. Multiple ways work, and
exceptions can be made to work for all error checking, but this was
not the point of my post.

Also true. On the other hand, if every function returns an error code, then
you have to check for, and handle, every possible failure (or ignore the
return codes which, I suspect, we all do far too often!). I think it was
Steve Maguire in his book "Writing Solid Code" that suggested that you write
functions that can't fail. Obviously, this is an impossible task, but the
spirit of his suggestion can be accomplished by using exceptions. Write
your functions as robustly as possible, then call them *as if* they can't
fail. If they do, let some exception handler further up the call tree take
care of processing the error condition.

That sounds like an awful lot of overhead for some very simple
things. I am reading an article by Alexandrescu, mentioned in a
previous post in this thread. I think I would tend to agree with his
point: "This approach works just fine, but in the real world, it turns
out not to be that neat. You must write a bunch of little classes to
support this idiom. Extra classes mean extra code to write,
intellectual overhead, and additional entries to your class browser.
Moreover, it turns out there are lots of places where you must deal
with exception safety. Let's face it, adding a new class every so
often just for undoing an arbitrary operation in its destructor is not
the most productive."

True again. But for non-trivial cases, it is much easier and much safer to
write an RAII class to handle cleanup. If you have to write the cleanup
code anyway, you might as well do it once, encapsulate it, get it right, and
never worry about it again. And if your code does encounter a true
exception, you're that much better off.

- Dennis
 
J

jeffc226

Also true. On the other hand, if every function returns an error code, then
you have to check for, and handle, every possible failure (or ignore the
return codes which, I suspect, we all do far too often!).

Right. I can't say I've comfortably settled into a coherent
philosophy yet....
 
G

Gavin Deane

This is like saying "If you didn't expect to get stabbed while walking
down the street, then why does the hospital need an emergency room?
An exception is essentially an emergency.

I think that my being stabbed in the street is definitely something
that could occur, but probably not something that would occur.

You said "errors that you don't expect could occur". It's possible you
meant "errors that you don't expect would occur". That's quite a
difference, although the latter still has the problem of being vague
about the level of probability of occurance at which exceptions become
preferable to return codes. And even if you quatified the
probablility, I still don't think that's the criterion for choosing
between the two means of error handling.
The definition of an emergency is something that we know might occur
but can't be predicted. According to Webster "an unforeseen
combination of circumstances".

Clearly that definition isn't appropriate here. You have forseen the
"emergency" otherwise you wouldn't be writing an exception handler to
deal with it.
I really don't think using exceptions for all error cases is a very
good idea.

Neither do I, and I didn't day that. I said they allow you to cleanly
separate error handling code from other code. If the error handling
code does not need to be separated, the ability to separate it cleanly
is not relevant.
If someone logs in and enters a bad password, you are
going to throw an exception? That is hardly "unforeseen".

I might, or I might not. Whether it is forseen or not is going to play
less of a part in that decision than whether the code that handles the
error is logically and physically (e.g. in call stack terms) distant
from the code that detects the error - or to put it another way, will
using exceptions instead of return codes lead to more readable or less
readable code? I suspect for an incorrect password where the responce
is to prompt the user to try again, the error handling code would be
in the same place so exceptions would offer no advantage. On the other
hand, the code to handle the situation where the password is incorrect
three times in a row and the user is locked out could be separate and
in this case using an exception might lead to cleaner code.
We can
debate endlessly about what might be "foreseen" and what might not be
"foreseen".

Indeed we can, and people do. And it is because of this endless debate
that never reaches a satisfactory conclusion that I think the
principle you brought up is not helpful.
We typically write a boolean function (that returns a
boolean value.) Such a function should not be replaced by a void
function that throws an exception, IMO.

If you have several such functions, calling each other down to a
number of levels, and some failures need to be reported all the way
back up the call stack, you end up with precisely the nightmare of
nested ifs and so on that your original question was looking for a
solution to. In this situation, exceptions *are* the solution.
Multiple ways work, and
exceptions can be made to work for all error checking, but this was
not the point of my post.

Nor mine.
That sounds like an awful lot of overhead for some very simple
things. I am reading an article by Alexandrescu, mentioned in a
previous post in this thread. I think I would tend to agree with his
point: "This approach works just fine, but in the real world, it turns
out not to be that neat. You must write a bunch of little classes to
support this idiom. Extra classes mean extra code to write,
intellectual overhead, and additional entries to your class browser.
Moreover, it turns out there are lots of places where you must deal
with exception safety. Let's face it, adding a new class every so
often just for undoing an arbitrary operation in its destructor is not
the most productive."

I've only scanned it just now (I have read it beofer but I don't
recall the full detail), but it looks like that article is talking
about the extra workload involved in achieving the strong vs basic
level of exception safety. I was talking about cleaning up resources
for which failure to clean up would lead to a violation of the basic
exception safety guarantee (e.g. leaking memory, file handles etc.) -
which I think is *always* a bad thing and to which RAII is the general
solution.

The further point is that, unless you are very careful about the code
in your function (including what other functions it calls, whether
your own, third party or standard library), ensuring you have exactly
one return statement, at the end of the function, is not sufficient to
ensure a single exit point. If the "do some cleanup" code is
essential, putting it at the end of the function, immediately
preceding the return, is not appropriate unless you can be certain of
reaching that point in your function without an exception being
thrown.

Whether for any particular piece of code you want to go up from basic
to strong exception safety is a decision to be made on a case by case
basis. It has costs and benefits that cannot be generalised.

Gavin Deane
 
J

jeffc226

You said "errors that you don't expect could occur". It's possible you
meant "errors that you don't expect would occur".

Maybe I did, can't remember. But one recommended usage of assertions
is covering cases that you think are really silly, because you assume
they can't happen. So in theory the idea has some sort of merit.
Obviously if it's truly mathematically impossible for something to
happen, then it need not be considered.
Clearly that definition isn't appropriate here. You have forseen the
"emergency" otherwise you wouldn't be writing an exception handler to
deal with it.

I suppose we're being pedantic, but you haven't explained the
existence of "Emergency Rooms" at hospitals. If you call them
misnomers, still there are many "emergency procedures" in place in the
world to handle events that are correctly defined as emergencies.

That doesn't prove exceptions are or should be emergencies. I have no
problem with using exceptions for basic error handling if it's part of
a consistent strategy, as you seem to use them. I'm just saying the
original principle I described exists (whether or not I or you agree
with it), and the idea that it's a debatable principle doesn't mean
it's invalid.
 
G

Gavin Deane

I suppose we're being pedantic, but you haven't explained the
existence of "Emergency Rooms" at hospitals. If you call them
misnomers, still there are many "emergency procedures" in place in the
world to handle events that are correctly defined as emergencies.

I can't explain their existence by analogy to C++ error handling
mechanisms because I simply don't see a connection. I am aware of the
"use exceptions for exceptional circumstances" idea, but I am not
aware of anything behind the idea - just those headline words. There
is nothing in my personal experience of programming, maintaining or
reading what other people have to say that has given me any inkling of
how those who advocate the idea intend that I should distinguish, on a
case by case basis, between cases where exceptions are appropriate and
cases where they aren't. On the other hand, while not being
mathematically quatifiable, simplicity and readability of code are
familiar concepts usually at the forefront of my mind. I am well aware
of what they mean, well aware of their advantages and well aware of
how, in some situations, using exceptions for error handling can help
me achieve them.
That doesn't prove exceptions are or should be emergencies. I have no
problem with using exceptions for basic error handling if it's part of
a consistent strategy, as you seem to use them. I'm just saying the
original principle I described exists (whether or not I or you agree
with it), and the idea that it's a debatable principle doesn't mean
it's invalid.

I question its validity not because I am skeptical of the benefits of
applying the principle, but because, far more fundamentally, I am
skeptical that anyone can tell me *how* to consistently apply the
principle so that I may even assess its benefits. My question is
whether there is any meaning (not necessarily mathematically precise,
but clear enough to be communicated reliably from one person to
another) behind the slogan "use exceptions for exceptional
circumstances". If there is, I haven't seen it and I don't think it's
for want of looking.

Gavin Deane
 
N

Noah Roberts

Gavin said:
If you have several such functions, calling each other down to a
number of levels, and some failures need to be reported all the way
back up the call stack, you end up with precisely the nightmare of
nested ifs and so on that your original question was looking for a
solution to. In this situation, exceptions *are* the solution.

I disagree. Assuming that the boolean function is doing what it's
supposed to. In that it tries something and reports success/failure.
Apparently for this case, at that level, either is pretty much as likely
as the other. This isn't a good case for exceptions and shouldn't be
changed to report them.

On the other hand...

Maybe you are calling that function from a file reader that is reading a
format you invented. At this point in the code we could say we know the
format is the expected type we intend to read so failure here is an
exceptional situation. Then at this point we can throw an exception if
the function fails.

This makes your reader (let's assume that's what the function
does..parses something) function usable at both levels...where it could
normally fail and where it isn't normal for it to fail. You have one
level of ifs in both situations and are not required to use an exception
in say ... a dialog handler where it's just ugly.

If you change the function to toss an exception instead of report a
status you tie that function to a particular use. I think the question
of exceptionality is specific to a particular function...not it's clients.
 
G

Gavin Deane

I disagree. Assuming that the boolean function is doing what it's
supposed to. In that it tries something and reports success/failure.
Apparently for this case, at that level, either is pretty much as likely
as the other. This isn't a good case for exceptions and shouldn't be
changed to report them.

I think if success and failure are broadly as likely as each other, it
is unlikely that the response to failure and the response to success
should logically be handled in completely different areas of the code.

Sometimes, the code that performs some action and the code that
handles failure of that action are distant from each other in terms of
program structure, and you need a way to travel that distance when
failure occurs. You could do that by traversing the program structure
one step at a time with return codes, or you could get there in one
clean step by throwing an exception. This is what I mean by
readability being the criterion for deciding between error handling
mechanisms.

But I wouldn't recommend exceptions when the code handling success and
the code handling failure are structurally close. The advantage of
exceptions is that they can move you very cleanly to a different point
in the program structure. If you don't want to go to a different point
in the program structure that's not going to be relevant to you.

Gavin Deane
 
N

Noah Roberts

Gavin said:
I think if success and failure are broadly as likely as each other, it
is unlikely that the response to failure and the response to success
should logically be handled in completely different areas of the code.

Depends on if failure is an error. If you fail to parse a telephone
number is that an error? When parsing a file that expects there to be a
phone number then probably; when getting user input probably not since
one should expect the user to enter bad values. It is especially not an
error at parse point when you could be using the function in something
like: is it a phone number or an email address?

Use exceptions for error handling. Not all failures are errors.
 
G

Gavin Deane

Depends on if failure is an error. If you fail to parse a telephone
number is that an error? When parsing a file that expects there to be a
phone number then probably; when getting user input probably not since
one should expect the user to enter bad values. It is especially not an
error at parse point when you could be using the function in something
like: is it a phone number or an email address?

Use exceptions for error handling. Not all failures are errors.

I have no desire to use exceptions for everything. The problem I have
with using exceptions for "errors not failures" or "only in
exceptional circumstances" is knowing what those words mean. In
contrast, I know exactly what readability means because it is a
concept I deal with constantly whenever I am programming.

If I start a new program that involves some file parsing, I don't find
it helpful to think about what probability threshold a particular
class of failure must pass for exceptions to be appropriate, then
assess the actual probability of each class of failure against that
threshold. I do find it helpful to look at the design and identify
areas where the transition from detection of failure to error handling
to appropriate following action is made cleaner by the use of
exceptions than error codes.

The end result is probably the same. It's the thought process in the
decision making that's different, because the "only in exceptional
circumstances" logic doesn't give me any criteria I understand.

Gavin Deane
 
N

Noah Roberts

Gavin said:
I have no desire to use exceptions for everything. The problem I have
with using exceptions for "errors not failures" or "only in
exceptional circumstances" is knowing what those words mean. In
contrast, I know exactly what readability means because it is a
concept I deal with constantly whenever I am programming.

If I start a new program that involves some file parsing, I don't find
it helpful to think about what probability threshold a particular
class of failure must pass for exceptions to be appropriate, then
assess the actual probability of each class of failure against that
threshold.

It has nothing to do with probability and all to do with semantics.
Failure is either a common occurance or an error. "Readability" is no
less subjective.
 
G

Gavin Deane

It has nothing to do with probability and all to do with semantics.
Failure is either a common occurance or an error. "Readability" is no
less subjective.

It's no more subjective either. The difference is that I know how to
apply the abstract concept of readability to any arbitrary programming
problem because I am used to thinking in terms of readability as a
matter of course (and, while it is subjective, I seem to be able to
work productively with other people so I must be getting it about
right). On the other hand, I know of no abstract principle that
distinguishes the different properties of a common occurance and an
error.

If you were refactoring some existing code that originally handled
failures with return codes, and you ended up with the handling several
levels higher in the call stack than the detection, with all the
intermediate levels made more complex with branches and conditions
depending on the state of these codes, would you refuse to even
consider exceptions solely because you've categorised this failure as
a common occurance not an error?

Gavin Deane
 
N

Noah Roberts

Gavin said:
It's no more subjective either. The difference is that I know how to
apply the abstract concept of readability to any arbitrary programming
problem because I am used to thinking in terms of readability as a
matter of course (and, while it is subjective, I seem to be able to
work productively with other people so I must be getting it about
right). On the other hand, I know of no abstract principle that
distinguishes the different properties of a common occurance and an
error.

If you were refactoring some existing code that originally handled
failures with return codes, and you ended up with the handling several
levels higher in the call stack than the detection, with all the
intermediate levels made more complex with branches and conditions
depending on the state of these codes, would you refuse to even
consider exceptions solely because you've categorised this failure as
a common occurance not an error?

If it isn't an error it has no place being handled like one, no?
 
G

Gavin Deane

If it isn't an error it has no place being handled like one, no?

If I'm understanding you correctly, you're logic appears to be:

Exceptions should only be used to handle errors.
The situation being handled is a common occurance, not an error.
Therefore it is not appropriate to handle this situation with an
exception.

Impeccable logic, but only if one accepts the premise. That logic
tells me nothing about *why* exceptions should only be used to handle
errors and not common occurances. And that's before we've even got
into the question of needing to identify the generic properties that
distinguish the two.

The dialogue always goes like this...

Me: I consider using exceptions in any situation where their use makes
code clearer to understand.
Somebody else: Oh no, you can't do that. Exceptions are only for use
in exceptional circumstances.
Me: Why?
Somebody else: ... [blank look] ...

And that's it. I'm very willing to consider any response to the "Why?"
question, but I've never encountered one to consider.

Gavin Deane
 
K

Kai-Uwe Bux

Gavin said:
If it isn't an error it has no place being handled like one, no?

If I'm understanding you correctly, you're logic appears to be:

Exceptions should only be used to handle errors.
The situation being handled is a common occurance, not an error.
Therefore it is not appropriate to handle this situation with an
exception.

Impeccable logic, but only if one accepts the premise. That logic
tells me nothing about *why* exceptions should only be used to handle
errors and not common occurances. And that's before we've even got
into the question of needing to identify the generic properties that
distinguish the two.

The dialogue always goes like this...

Me: I consider using exceptions in any situation where their use makes
code clearer to understand.
Somebody else: Oh no, you can't do that. Exceptions are only for use
in exceptional circumstances.
Me: Why?
Somebody else: ... [blank look] ...

And that's it. I'm very willing to consider any response to the "Why?"
question, but I've never encountered one to consider.

Since I do not subscribe to the point you question, I might not be
well-posed to answer your call. I will try nonetheless. I know the
following reasons:

a) Code is meant to communicate intent. Since, for better or worse,
exceptions have been popularized by the powers that be as a mechanism for
error handling only, it is wise to follow that rule. Violations are bound
to create misleading expectations in those reading the code.

b) Similarly, because of the wide-spread perception that exceptions are
rare, many compilers tend to heavily optimize for the non-throw path of
control flow. Thus, using exceptions can be quite expensive.

c) The try-throw-catch mechanism is a glorified goto, except that it is even
worse: with a goto, at least you know where you jump. The dangers posed by
exceptions for maintainable programming are quite similar to those of goto.
Try-throw-catch introduces global dependencies in your code, i.e., it
becomes hard to understand the program in local terms, like what is going
on in the few lines on my screen. Therefore, strict coding guidelines
should accompany the use of exceptions. The rule to use them for
error-reporting only is a successful proposal in this regard. Weakening it
to: "write code that is easy to understand" is too permissive and will lead
down a slippery slope (as it does with goto). However, it is true that a
restrictive criterion can be inconvenient at times. This is just the price
you have to pay to confine the threat.


As for myself, I think that rules regarding try-throw-catch are coding
styles and should be local to a project, shop, community, etc. I don't
think that there is any valid technical reason to restrict try-throw-catch
to error handling. It has become a tradition, and following that tradition
is by and large a good thing if you want to work smoothly with others. Had
the C++ community set out to find interesting ways of using exceptions (as
it has done with templates), compilers would optimize differently and your
fellow programmers would read your code differently. But this has not
happened.


Best

Kai-Uwe Bux
 
N

Noah Roberts

Gavin said:
Impeccable logic, but only if one accepts the premise. That logic
tells me nothing about *why* exceptions should only be used to handle
errors and not common occurances.

You said it yourself.

So that error handling and normal program logic are not intermingled.

Second, there's the performance issue...exceptions can throw slow and do
in at least one common implementation.
 

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

Similar Threads


Members online

Forum statistics

Threads
473,813
Messages
2,569,696
Members
45,488
Latest member
MohammedHa

Latest Threads

Top