Error codes vs. exceptions

L

Luca Risolia

Elegant maybe, but potentially very expensive if used injudiciously.

This is true. In that particular case, there might be much space for
compiler optimizations. It would be interesting to know how it performs
compared to a traditional recursive search.
 
I

Ian Collins

This is true. In that particular case, there might be much space for
compiler optimizations. It would be interesting to know how it performs
compared to a traditional recursive search.

Measurement would be the only way to know and there would probably be a
(probably large) data size beyond which throwing an exception would be
faster.
 
R

Rui Maciel

Luca said:
What is elegant is a matter of opinion. Exceptions are not intended to
handle errors only, not according to authors like Stroustrup at least,
from whom I deliberately took one of the corner cases. Of course you
have to consider every case *cum grano salis*, I did not mean to say
that exceptions should always be used to control the program logic:

"Using exceptions as alternate returns can be an elegant technique for
terminating search functions – especially highly recursive search
functions such as a lookup in a tree."

from paragraph 14.5, "Exceptions that are not errors" ("The C++ Prog.
Language" 3rd ed.)

If you continue reading that part, you will notice that it goes as follows:

«However, such use of exceptions can easily be overused and lead to obscure
code. Whenever reasonable, one should stick to the ''exception handling is
error handling'' view. When this is done, code is clearly separated into
two categories: ordinary code and error-handling code. This makes code more
comprehensible.»

Then, if you read the chapter as a whole, you will realize that the use of
exceptions as "simply another control structure" is depicted as an oddity
instead of a reasonable or even desireable application, and this sort of use
is far from being endorsed by the author. And the reason is quite straight-
forward; employing exceptions as control structures is a bit of a hack
which, although it might appear to be a clever trick, doesn't really do
anyone any good.


Rui Maciel
 
L

Luca Risolia

If you continue reading that part, you will notice that it goes as follows:

...which does not contradict what I said. I think we are saying the same
thing.
 
N

Nobody

I've heard about this, and wonder when is it right to use codes, and
when to use exceptions for reporting errors? I've heard various stuff,
such as that exceptions should only be used to indicate "exceptional"
conditions. Yet what does that mean?

It usually means that the condition will rarely occur in practice.

Performance-wise, exceptions are costly if the exception is actually
thrown but free if not thrown, while a status return has a constant
overhead. If the condition rarely occurs, exceptions will work out
cheaper; if the condition is common, returning a status will be cheaper.

But performance is seldom the main issue. If throwing an exception means
that typical code will just wrap the call in a try/catch block, you should
use a status return instead. If typical code will propagate errors up the
call stack, you should probably use an exception.

It's all about code structure. If exceptions make your code cleaner by
reducing the amount of error-handling code, use exceptions. If they just
mean that you replace if/else with try/catch, then use a status return.
 
B

BGB

It usually means that the condition will rarely occur in practice.

Performance-wise, exceptions are costly if the exception is actually
thrown but free if not thrown, while a status return has a constant
overhead. If the condition rarely occurs, exceptions will work out
cheaper; if the condition is common, returning a status will be cheaper.

pretty much.

a status code also has the advantage if the return value is used to
drive logic in the caller, such as knowing when a task has finished,
when a desired item has been found, ...

But performance is seldom the main issue. If throwing an exception means
that typical code will just wrap the call in a try/catch block, you should
use a status return instead. If typical code will propagate errors up the
call stack, you should probably use an exception.

agreed.

exceptions work much better for transferring control across multiple
levels of call frames.

if the handler logic is directly in the caller, then it is less convenient.


similarly, there may be the matter of seriousness:
if the situation is "serious" (as-in, could potentially compromise
correct functioning of the application), then an exception may make more
sense;
if the situation is something which could be reasonably ignored with
little or no consequence, then a status code may make more sense.

It's all about code structure. If exceptions make your code cleaner by
reducing the amount of error-handling code, use exceptions. If they just
mean that you replace if/else with try/catch, then use a status return.

yep.

this is often what would happen in many cases, using a try/catch as a
slightly longer, and slower, alternative to an if/else block.
 
B

BGB

<snip rest>

I am not here to argue about nitpicking.

if the other posts in this thread are noted, the tradeoff depends on:
what one is doing in a given case;
which is more convenient in a given case.

try/catch is not always more convenient than if/else, and has tradeoffs
for when and where they might be used.


but, oh well, whatever...

relax, man.
 
A

Adam Skutt

pretty much.

a status code also has the advantage if the return value is used to
drive logic in the caller, such as knowing when a task has finished,
when a desired item has been found, ...

Or you just return the item and avoid the need for status altogether.
Success should be normally be implicit.
agreed.

exceptions work much better for transferring control across multiple
levels of call frames.

if the handler logic is directly in the caller, then it is less convenient.

You've said this a whole bunch of times but never once demonstrated
how this is actually true. I can think of a few cases where it's
true, but they're all pretty contrived.
similarly, there may be the matter of seriousness:
if the situation is "serious" (as-in, could potentially compromise
correct functioning of the application), then an exception may make more
sense;
if the situation is something which could be reasonably ignored with
little or no consequence, then a status code may make more sense.

As I've explained to you before, it's normally impossible for the
function issuing the error to tell the difference between these two
situations. Again, you've never once demonstrated how to apply this
reasoning to writing correct, usable code.

Adam
 
A

Adam Skutt

It usually means that the condition will rarely occur in practice.

I don't like this definition, personally. Yes, it is true that the
sort of events that typically cause exceptions are rare. However,
that fact doesn't do us much good when actually designing software.
But performance is seldom the main issue. If throwing an exception means
that typical code will just wrap the call in a try/catch block, you should
use a status return instead.

No, what you should do is return an actual useful value to the
caller. It is enormously difficult for a function writer to
accurately predict where and how any given "exceptional" condition
will be handled, so this line of reasoning is rather dubious at best.
You're welcome to provide an example, though.
It's all about code structure. If exceptions make your code cleaner by
reducing the amount of error-handling code, use exceptions. If they just
mean that you replace if/else with try/catch, then use a status return.

If you are replacing if/else with try/catch I'd likely argue that your
C++ code was most likely designed wrong in the first place.

Adam
 
R

Rui Maciel

Luca said:
..which does not contradict what I said. I think we are saying the same
thing.

I was pointing out that it is bad form to try to shoe-horn exceptions as
control structures, and therefore it isn't a good idea to depict this sort
of use as reasonable or acceptable, let alone elegant. As a control
structure, exceptions are like a rube goldberg machine, and it isn't a good
idea to advertise rube goldberg machines as something other than
entertaining gimicks. They may be cleverly built, they may work, but there
are plenty of alternatives which are far simpler, efficient and easier to
maintain.


Rui Maciel
 
B

BGB

Or you just return the item and avoid the need for status altogether.
Success should be normally be implicit.

only if one knows that the function will almost always succeed (IOW:
succeeding is part of its "definition of operation").

if it may also fail as part of its normal/expected operation, then it no
longer is so clear cut.


succeeding/failing need not be the same as an error/non-error condition,
but may be due to other factors (such as an item not already being in a
list or hash-table and needing to be created, ...).

not all status codes indicate errors as well, and there may actually be
successful status codes as well (traditionally these are distinguished
You've said this a whole bunch of times but never once demonstrated
how this is actually true. I can think of a few cases where it's
true, but they're all pretty contrived.

I make heavy use of code driven by "predicate functions" (functions or
methods which return a boolean value to indicate status), which are
arguably the same sort of thing as what you are arguing against.

it is all a fairly pointless and nit-picky argument at this point.


As I've explained to you before, it's normally impossible for the
function issuing the error to tell the difference between these two
situations. Again, you've never once demonstrated how to apply this
reasoning to writing correct, usable code.

usually a person writing an application will know what the code in the
thing is going to be doing, as well as the consequences of a given
operation succeeding or failing.

usually it is also "fairly obvious" from what the function is going to
be doing as well.


now, I am not opposing using exceptions here, by any means, as there are
many cases where they do make sense (namely, cases where the situation
*actually is* unexpected or abnormal).

for example:
running out of memory, or detecting a problem with the heap, is
something a bit more worthy of an exception.
 
A

Adam Skutt

only if one knows that the function will almost always succeed (IOW:
succeeding is part of its "definition of operation").

if it may also fail as part of its normal/expected operation, then it no
longer is so clear cut.

Nonsense. Trivial example: opening a file is an operation where it is
impossible to know whether success is possible until the operation is
attempted. Yet, opening a file should throw an exception if it fails
because there's no reasonable expectation that the caller can handle
the failure--there's no reasonable expectation that the program can
handle the failure at all.

The question is whether people want to write as if the function almost
always succeed, which is overwhelmingly the case. We go through great
length to create these abstractions all the time. Exceptions are just
one example of many.
succeeding/failing need not be the same as an error/non-error condition,
but may be due to other factors (such as an item not already being in a
list or hash-table and needing to be created, ...).

Huh? This is literal nonsense.
not all status codes indicate errors as well, and there may actually be
successful status codes as well (traditionally these are distinguished
by sign, where <0 means failure, and >=0 means success).

Yes, and are traditionally used where returning the desired value is
impossible/difficult or the error handling semantics mandate a
successful status code. They have very little value in idiomatic C++.
I make heavy use of code driven by "predicate functions" (functions or
methods which return a boolean value to indicate status), which are
arguably the same sort of thing as what you are arguing against.

Without context, how am I supposed to know?
it is all a fairly pointless and nit-picky argument at this point.

Hardly. Error handling is pretty fundamental to how one designs and
writes code. Calling something "pointless" and "nit-picky" just
because you lack any reasonable support for your position is pretty
childish behavior on your part, though, especially when you choose to
continue the discussion!
usually a person writing an application will know what the code in the
thing is going to be doing, as well as the consequences of a given
operation succeeding or failing.

No. If I write a library to parse JPEG files, I have no clue what the
applications that use my library will do with my code (beyond parse
JPEG files).

Even if the code isn't mean to be shared between multiple
applications, I may have different error handling in different parts
of the application. Failing to open a configuration file may be
fatal; while failing to open a file specified by the user allows the
operation to be retried, /if a user exists/. Terminating the program
if a system call is interrupted may be appropriate if the program is
run on the console; it may not be appropriate if the program is run as
a service or GUI application.

As a result, the file opening routine must necessarily provide error
handling semantics that allow for all of these behaviors. As a
result, you pretty quickly end up in the same situation that I
describe: the routine cannot assume anything about where and how
"exceptional" situations will be handled when they occur.
now, I am not opposing using exceptions here, by any means, as there are
many cases where they do make sense (namely, cases where the situation
*actually is* unexpected or abnormal).

for example:
running out of memory, or detecting a problem with the heap, is
something a bit more worthy of an exception.

The fact you think two things that essentially cannot be handled[1]
are good examples of when exceptions are appropriate says more about
your position than anything else you've said.

Adam

[1] Or actually cannot be handled, in many cases. May the OOM killer
forever reap your leaky processes.
 
J

Jorgen Grahn

["Followup-To:" header set to comp.lang.c++.]
Are you asking specifically about C++?  I will assume "yes", but I get
a bit confused by your crossposting to comp.programming -- what's the
proper use of exceptions varies between languages (and cultures).

Yes, my eye was toward C++.

I don't think you should try use the idea of "exceptional" conditions
as a strict rule to apply. IIRC it was something Stroustrup came up with
to explain how he thinks about it, but it's vague; you can debate
what's exceptional or not for years.

Some things are hard to set up general rules for.  You have to deal
with them on a case-by-case basis.
<snip>

But what is the process for dealing with each case? You need some
way to reason about the cases.

The only answer I can give is "experience". I'm sorry; I know it's a
non-answer. But I haven't seen an answer yet (in books and here) which
has satisfied me.
What happens if we do that -- take steps elsewhere to make sure
those requests don't happen? As that just makes sense to do.

I meant to say that's yet another reason to use an exception, named
something like InterfaceViolationYourFault ...
The trouble with error codes, as I see it, is that they can lead to
lots
of duplicated code. If you have a function that makes several calls
to error-code-returning functions, then you need a handler around
EVERY call.

Yes, we know ... or at least *I* do. I'm fighting a huge piece of C
code right now which is mostly error handling -- and not even
*appropriate* error handling, just "log a message and return error to
the caller".

....
Yet the approach I was using seems like a silly one (error codes
for everything but what returns a value/constructors/etc.). "Silly"
because it doesn't seem consistent or "inconsistent but in the right
way". It means you could be easily, haphazardly mixing together
operations that give error codes and that throw exceptions without
any overarching logic.

Well, if you cannot find a general rule, then you still have to
make up design rules for your specific piece of software. "We'll use
exceptions for <these> things, but not for <these>." It's easier
to come up with project-specific rules: you know the people involved,
you know the environment, the robustness requirements and so on.
And also, I've noticed that with this "mix error codes and exceptions"
thing, that I seem to find myself adding a translation layer to
translate
between the two and having a corresponding exception object for every
error code, which makes it more difficult to add new exception/error
conditions since we have to update all those lists. Is this the wrong
way
to go about it? If so, what's a better way to?

That seems wrong, and I can't understand why it's happening. Error
codes (to me) should be quite isolated to specific subsystems or areas.
Like, if you do socket programming you have the API's I/O error codes
(from errno etc) at the bottom, but further up you have higher-level
exceptions like "file transfer failed", "failed to login" or "NNTP
session lost".

/Jorgen
 
J

Jeff Flinn

Hi.

I've heard about this, and wonder when is it right to use codes, and
when to use exceptions for reporting errors?...

The best advice I've seen is from
http://www.boost.org/community/error_handling.html

"The simple answer is: ``whenever the semantic and performance
characteristics of exceptions are appropriate.''

An oft-cited guideline is to ask yourself the question ``is this an
exceptional (or unexpected) situation?'' This guideline has an
attractive ring to it, but is usually a mistake. The problem is that one
person's ``exceptional'' is another's ``expected'': when you really look
at the terms carefully, the distinction evaporates and you're left with
no guideline. After all, if you check for an error condition, then in
some sense you expect it to happen, or the check is wasted code.

A more appropriate question to ask is: ``do we want stack unwinding
here?'' Because actually handling an exception is likely to be
significantly slower than executing mainline code, you should also ask:
``Can I afford stack unwinding here?'' For example, a desktop
application performing a long computation might periodically check to
see whether the user had pressed a cancel button. Throwing an exception
could allow the operation to be cancelled gracefully. On the other hand,
it would probably be inappropriate to throw and handle exceptions in the
inner loop of this computation because that could have a significant
performance impact. The guideline mentioned above has a grain of truth
in it: in time critical code, throwing an exception should be the
exception, not the rule."

Jeff
 
A

Adam Skutt

I disagree.   Everthing I've written can handle an open failure, in
one way or another.

If what you said is true, then you can readily tell me what I should
do when getting ELOOP, or ENAMETOOLONG, etc. from open(2) in an
application that's run from cron job? There's no user to prompt so
the only recourse here is termination or moving on to the next input,
if there even is a next input.

Nevermind EOVERFLOW, where your only solution is termination since the
application must be recompiled.

Plus, I seriously doubt your applications has sensible and correct
handling of ENFILE or ENOMEM (if you even get to see it). Even if
they do, it's irrelevant anyway (twice over). UNIX syscalls contain
all sorts of error codes that you will either a) never practically see
b) won't be able to do anything about them if you do see them.
I don't subscribe to the windows model of death
on error.

The Windows model is no such thing. Even if it were, it doesn't
change the fact that many applications are run in contexts where they
have no ability to correct invalid input: they simply must reject it.
Termination is a perfectly cromulent way to reject invalid input for
many applications in these situations.

Even in contexts where the program could correct invalid input, it
seems stupid to add a input loop to mv(1), ln(1), etc. just because
the user typed in the wrong file name. The shell already has a
command loop, so why bother?

Adam
 
I

Ian Collins

<snip rest>

I am not here to argue about nitpicking.

if the other posts in this thread are noted, the tradeoff depends on:
what one is doing in a given case;
which is more convenient in a given case.

try/catch is not always more convenient than if/else, and has tradeoffs
for when and where they might be used.

I doubt anyone would disagree about that.

One key driver is how close to the source of the error can it be
handled. For example code that expects a configuration file to be
present but can supply defaults if it is missing shouldn't use
exceptions. If there isn't a plan B, it should.
 
B

BGB

I doubt anyone would disagree about that.

One key driver is how close to the source of the error can it be
handled. For example code that expects a configuration file to be
present but can supply defaults if it is missing shouldn't use
exceptions. If there isn't a plan B, it should.

generally agreed.
 
A

Adam Skutt

mv/cat/ln handle ENOENT-category errors perfectly.   I would never advocate different.

Yes, by terminating. Which means you cannot disagree with what I
said!

There's no sense in responding to anything else you said if you're
going to be this blatantly dishonest.

Adam
 
P

Pavel

mike3 said:
Hi.

I've heard about this, and wonder when is it right to use codes, and
when to use exceptions for reporting errors? I've heard various stuff,
such as that exceptions should only be used to indicate "exceptional"
conditions. Yet what does that mean? I've heard that, e.g. a user
inputting invalid input should not be considered "exceptional", but
something like running out of memory should be. Does this mean that if
we have a program, and we have a "parse()" function that parses a
string input by the user, that this function should return an error
code on parse failure, instead of throwing an exception? Yet we'll
probably also come across places where it's good to use an exception,
in the same program! Which means we get into _mixing error codes and
exceptions_. And what's the best way to do that?

Also, how exactly does one go about determining what is and is not
"exceptional"? Two examples were mentioned of things exceptional and
non-exceptional, but what about something else, like say in a game,
where you have a grid representing a game level, and a request for a
tile of the level is made with a coordinate that is off the map (like
a 64x64 map and something requests a tile at (100, 100).). Would it be
OK for the function working on the tile to throw? Or should it give an
"out of range" error code? And as for that mixing: consider, e.g. C++
and probably many other languages: a function has a single definite
return type. Suppose our grid had a function that extracts an
attribute from a cell. What to do when there's an out-of-bounds
request? Throw exception? See, what I've currently been doing, and
it's probably silly, is to use exceptions when our function needs to
return a value, and error codes when it could otherwise return "void".
This doesn't seem like a good idea. But what to do? Make every
function return an error code, using pointers to output variables to
store output, and only use exceptions for a rare few kinds of "system-
related" error? Yet one can hardly deny the niceness of being able to
say "x = f() +<foo>" (inside a "try" block, perhaps) instead of

if(f(&x) != SUCCESS)
{ // handle error }
x += foo;

:)

Note how we can easily get LONG methods full of repeated code with
error codes (repeated error handlers to handle similar errors at
various function calls calling error-code-emitting functions, if one
wants to be more graceful than simply aborting with an error to the
next level up (which complicates what error codes a function can
return, since it can return its own codes in addition to those
returned by the functions below it, and those may have functions below
THEM, and so on...).). And who likes duplicated code? eww. This seems
a disadvantage of error codes.

Or, and this is what I've been thinking of, use exceptions for every
error that the user does not have control over, like invalid input
strings. Would that be OK or excessive use of exceptions? And if we
are to mix error codes and exceptions, does this mean we should have
the lists of codes and exceptions correspond + a translator to
translate between the two?

I know you have already received lots of advice; but I think they omit an
important factor, namely whether you are writing a library. In my experience, I
found it quite annoying when the API of a library I use can throw. Catching all
possible exceptions after every call is even more disrupting than processing
return codes and letting them through often creates a mess with multiple error
processing policies coming from different libraries or from my application and
library or libraries it uses.

In addition, a library writer does not always know the performance requirements
of the future client code, especially if it is going to be a successful library
and calling throwing function incurs overhead.

Using "golden rule", I refrain from exposing exceptions in APIs to my libraries
and strive to make all top-level functions nothrow regardless of whether or not
I use them inside the library implementation.

HTH,
-Pavel
 
N

Nobody

I know you have already received lots of advice; but I think they omit an
important factor, namely whether you are writing a library. In my
experience, I found it quite annoying when the API of a library I use can
throw. Catching all possible exceptions after every call is even more
disrupting than processing return codes and letting them through often
creates a mess with multiple error processing policies coming from
different libraries or from my application and library or libraries it
uses.

That's a non-issue for exceptions which should never need to be thrown
in the first place, e.g. an invalid argument value. If you don't want to
have to catch such exceptions, don't cause them to be thrown.

Even where it is an issue, any API design involves trade-offs. Having
every function return a status indication may be more efficient for code
which always handles failures directly in the caller. OTOH, it imposes a
significant burden on code which would otherwise just allow an exception
to propagate up to a higher level.

It's impossible to provide a hard-and-fast definition of which conditions
are "exceptional", particularly for a library. OTOH, it's equally
impossible to provide a hard-and-fast rule regarding the side on which to
err.

Treating any condition which might conceivably be caught in the immediate
caller as non-exceptional is likely to result in a rather inconvenient API
for the majority of code. I mean, the STL *could* have a given every
container type a "bad bit" (in the same vein as iostream) to indicate
allocation failure, but I'm rather glad it didn't.
 

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

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top