Error codes vs. exceptions

A

Adam Skutt

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

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


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

Except that your guidance doesn't apply here. Modern C++ runtimes
incur no execution overhead for exception handling unless an exception
is actually thrown. Since the goal is to terminate the loop entirely,
an exception would be perfectly reasonable in principal. Where it
might unreasonable is if the exception were to be caught and then
computation resumed. However, it's pointless to assume throwing an
exception will be a problem without measuring.

Adam
 
A

Adam Skutt

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.

Exceptions: you are doing them wrong. You should only catch the
exceptions you are interested in, and in general, I've rarely (ever?)
needed to catch more than one class at a time. In fact, I'd generally
assume (in C++) that needing to catch more is indicative of a design
problem.
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.

It's senseless to cater to such senseless micro-optimizations unless
you must. Modern C++ implementations don't incur execution overhead
unless an exception is actually tossed. I assume you don't use
libraries that use virtual functions as well because of the same
potential problem?
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.

I have to imagine either your libraries are therefore very difficult
to use idiomatically or aren't actually nothrow safe.

Adam
 
A

Adam Skutt

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 by, "shouldn't use exceptions," you really mean, "Since the
operation cannot 'fail', there's no need to throw an exception". The
other unspoken side of the coin is that there is no reason to return a
status code, /for precisely the same reason/. The only thing the code
needs to return is the configuration data.

Adam
 
G

Guest

mike3 wrote:

[...] an important factor [is] whether you are writing a library.
In my experience, I found it quite annoying when the API of a
library I use can throw.

when i've written a library I've quite liked the idea that "at least the buggers (clients) can't ignore these errors!". Well up until I found code liberally sprinkled with

catch (...)
{ /* ignore */ }

:-(
Catching all possible exceptions after
every call is even more disrupting than processing return codes

a well written library shouldn't be returning lots of different exceptions- and it should docuemnt the ones it does.
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.

ah. I was going argue that should put less catchs in and write exception safe code. I haven't found the problem you describe. perhaps i haven't used a sufficiently rich mix of incompatible libraries.

<snip>
 
G

Guest

On Thursday, May 31, 2012 5:30:42 AM UTC+1, Adam Skutt wrote:

Exceptions: you are doing them wrong. You should only catch the
exceptions you are interested in, and in general, I've rarely (ever?)
needed to catch more than one class at a time. In fact, I'd generally
assume (in C++) that needing to catch more is indicative of a design
problem.

oh? so the application I did maintenance that had 12 different (no inheritance relationship) exception classes had design issues?
:)
 
M

mike3

On May 29, 1:08 am, Marcel Müller <[email protected]>
wrote:
Converting an error code into an exception might be a good idea. But the
other way around is most likely not.

And another rule of thumb: the number of exceptions thrown during the
processing of a complete request should be finite. I.e. it must not
scale with the amount of data processed.

Marcel

So does this mean we should have an exception class defined for every
error code, so we can do that "conversion"?
 
I

Ian Collins

On May 29, 1:08 am, Marcel Müller<[email protected]>
wrote:


So does this mean we should have an exception class defined for every
error code, so we can do that "conversion"?

That really depends what you intend to do when you catch one. I tend to
use an exception type for a family of error codes and include the actual
code in there. Most of my simple applications just catch the base
exception (std::runtime_error), send the result of what() to cerr and exit.

If the application can recover from a specific type of exception, I'll
catch those a perform whatever recovery or reporting is required.
 
S

Stefan Ram

Pavel said:
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.

And that leads to an answer to the OP's question: When in Rome do as the
Romans do! When in a programming language do as the standard library does!
Look at the standard library and observe what means it uses to signal
the status of attempts, and then use these means!

In C++, »standard library« here does not mean that part inherited from
C, but more that part written specifically for C++.
 
M

mike3

On 06/ 1/12 08:52 AM, mike3 wrote:

That really depends what you intend to do when you catch one. I tend to
use an exception type for a family of error codes and include the actual
code in there. Most of my simple applications just catch the base
exception (std::runtime_error), send the result of what() to cerr and exit.

If the application can recover from a specific type of exception, I'll
catch those a perform whatever recovery or reporting is required.

I.e. don't make exception classes for every error code but make them
for
a family of error codes?
 
G

Guest

I tend to do that too. I only define my own exception types if I want special handling or it's getting messy to pack all the information into a what() string.
I.e. don't make exception classes for every error code but make them
for a family of error codes?

these are rules of thumb rather than hard rules. I try to derive everyting from std::exception (or rather std::runtime_error which itself derives from std::exception). That way at the top of the program you can catch and report any exception.

Lots of catch(...)s are usually a sign that someone doesn't want to do proper exception handling.

Unless your program is enourmous I'd suggest starting with throwing runtime_error.
 
P

Pavel

Stefan said:
And that leads to an answer to the OP's question: When in Rome do as the
Romans do!
That's what I always profess. With exceptions, however, it might be unclear
where's Rome and where's Athens. Just a quick example off the top of my head:

When using STL, use std::exception hierarchy.
When using WFC, use System::Exception.
When using Qt, use return codes, but for passing errors between threads, inherit
your exceptions from QtConcurrent::Exception

I believe WFC, Qt and many recent implementations of STL all are high-quality,
mostly well-designed library; the first two are also immense in coverage. More
often than not it's not an option not to use them (or other libraries pertinent
to your application's domain).

Where is Rome?

When you write your own library that will most often used with WFC, often with
Qt and always with some STL -- how shall you expose your errors?

When you write your own library that uses WFC -- and of course STL how shall you
expose your library's errors and where should you catch std::exception (which
are fortunately rare) and guys from System::Exception hierarchy (which are much
more often)?

When you write an application that uses all 3 or even only two libraries -- what
errors shall you use inside your application? Many large application require
particular processing of particular error conditions (error logs, alarms,
interfaces to enterprise event handling systems, what's not) -- are you going to
proliferate these exceptions? Usually, you don't. The benefits of uniform error
processing aside, why will you want to make more parts of your code dependent on
the libraries only because their exceptions may penetrate them and the errors
are need to be processed there? What if you need to replace such a big library
with another monster (e.g. to port your library). How are you going to tear
these dependencies out?

If you are a responsible designer, you will provide your own error processing
layer and you will have to meticulously catch and either process or crack and
refactor all errors before letting them further in a thin layer wrapping the
library calls your application uses. The code to capture error codes is simpler,
shorter and faster than that needed to capture exceptions.

As a free bonus, you (or your user if you are the library writer) can always
make a choice between writing throw and nothrow functions at no coding cost.

On top of this, following the code that only calls nothrow methods is much
easier which increases the programmer's productivity. You know, programmers of
successful real-life applications and libraries (which is equivalent to saying
"applications and libraries of significant size") have to spend more time on
reading and understanding code of others than on writing their own code.

Do your math yourself. I did mine many years ago and have never had a reason to
be sorry of this my application of golden rule.
When in a programming language do as the standard library does!
Look at the standard library and observe what means it uses to signal
the status of attempts, and then use these means!

In C++, »standard library« here does not mean that part inherited from
C, but more that part written specifically for C++.

-Pavel
 
A

Alf P. Steinbach

Hi.

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

Use whatever's more clear and practical in any given case.

And note that "codes" include the case of zero information about what
failed, where there's only one success indicating code (like boolean
"true") and one failure indicating code (like boolean "false")...

Also note that there are many other techniques for handling failures
that occur in a function f:

* let f return a possibly empty result
e.g. check out Barton/Nackman "Fallible" and Boost "optional"


* let f call an error handling routine, that's possibly configurable
a great many libraries do this

* let f terminate the program
a bit harsh, but e.g. a JPEG library used by ImageMagick did this

* let f involve the user and try to fix the problem
this was used in Windows for missing removable media, missing
DLLs and so on, with a box that like DOS did earlier said "abort,
ignore, retry" (or the like)

* let f simply have undefined behavior
may sound pretty stupid but is used by e.g. the C++ standard library
for functions where failures only are caused by failed preconditions

Regardless, you have the option of letting f log the incident, or not.

But generally, e.g. when I'm going to call a C library function or
Windows API function that (as they typically do) has some ad hoc fault
indication + some error code scheme, then I usually wrap it in a
function or expression that throws a C++ exception. That's generally
more convenient even for local handling of the failure. And one main
reason is that it encapsulates and gets rid of all the myriad ad hoc
schemes for checking whether the function failed and for responding to
it -- it's a standardization and simplification.

As an example,

<code>
// `errno` may be an expression macro, so it cannot (portably) be
qualified with "::".
int stdErrno() { return errno; }
void clearStdErrno() { errno = 0; }

bool hopefully( bool const condition ) { return condition; }
bool throwX( string const& s ) { throw runtime_error( s ); }


long longFrom(
char const spec[],
int const radix = 0,
bool const acceptTrailingChars = false
)
{
char* pEndOfScan = 0; // The unsafe type is required by `strtol`.

clearStdErrno();
long const result = strtol( spec, &pEndOfScan, radix );
string const failureDescription = 0?string()
: pEndOfScan == spec?
"longFrom failed: the number spec was not accepted by
strtol()."
: stdErrno() == ERANGE?
"longFrom failed: the specified number value is too large
for strtol()."
: stdErrno() != 0?
S() << "longFrom failed: strtol() failed, errno = " <<
stdErrno() << "."
: *pEndOfScan != '\0' && !acceptTrailingChars?
"longFrom failed: extraneous character(s) after valid
number spec."
:
"";
hopefully( failureDescription.length() == 0 )
|| throwX( failureDescription );
return result;
}
</code>


As shown by the various exception messages there are (at least) 4 ways
that "strtol" can fail.

I would speculate that in many programs using the "strtol" function
directly, not all failure paths are checked -- but the wrapper
replaces the sequence of four ad hoc checks with simple standard C++
exception handling. Of course, with a C++11 conforming compiler there's
little need to call "strtol" because in C++11 iostreams do that for you
(C++03 instead used the "scanf" family, with possible Undefined
Behavior). But I think it illustrates the case for wrapping in C++.

So, C = preference for codes, error handlers functions etc., and C++ =
preference for exceptions. But in some cases, as with e.g. calls across
binary module boundaries, you can't assume C++ exception support. Then
you have to design for the code to be callable as C, i.e. no exceptions.

All that said, I'm primarily responding because I'm really curious about
where this great need for MECHANICAL RULES comes from?

If programming could be reduced to mechanical rules, if that was a good
idea, then, u know, it could be automated, and then you would not have
this problem of finding the rules because you wouldn't be programming:
it would be done by machine... So, instead of seeking mechanical rules
to be applied mindlessly, I suggest seeking up concrete EXAMPLES of
failure handling. Then apply INTELLIGENCE and understanding of concrete
situations that you face, and just strive to Keep Things Simple. ;-)


Cheers & hth.,

- Alf
 
B

BGB

Hi.

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

Use whatever's more clear and practical in any given case.

generally agreed.

And note that "codes" include the case of zero information about what
failed, where there's only one success indicating code (like boolean
"true") and one failure indicating code (like boolean "false")...

Also note that there are many other techniques for handling failures
that occur in a function f:

* let f return a possibly empty result
e.g. check out Barton/Nackman "Fallible" and Boost "optional"

possibly.



* let f call an error handling routine, that's possibly configurable
a great many libraries do this

seems good.

* let f terminate the program
a bit harsh, but e.g. a JPEG library used by ImageMagick did this

I personally consider this to be an unreasonable strategy in the general
case, since then a "reasonable" or even "trivial" issue may cause the
application to die, possibly without any way to recover short of the
application not using the library in the first place.


I have ended up dropping libraries in the past for pulling this sort of
thing (well, among other things).

like:
call library to load something from a file;
file fails to open;
library calls "abort()".

this is along with the annoyance of libraries which can only work with
files, but the data in question (in the application) is held in buffers
or similar.


* let f involve the user and try to fix the problem
this was used in Windows for missing removable media, missing
DLLs and so on, with a box that like DOS did earlier said "abort,
ignore, retry" (or the like)

in most cases, this probably shouldn't be done in library code (but
should probably be left up to the application).

it was an extra annoyance a while back trying to figure out how to go
about making Windows not throw up a dialog box whenever a
"LoadLibrary()" call failed to work (Windows just assumed that a
"LoadLibrary()" call failing was a serious problem, rather than, say,
this call being used to check for an optional component).

luckily, there was an option to disable said dialog.


* let f simply have undefined behavior
may sound pretty stupid but is used by e.g. the C++ standard library
for functions where failures only are caused by failed preconditions

possibly, in this case.

I generally prefer code which doesn't just randomly blow up though, if
possible (usually, about the only real cases it is a good idea to skip
over basic "sanity checks" is in cases of "potentially performance
critical" code).


fairly common in my case is that, if the code for whatever reason can't
do what is requested, it will function as a no-op and indicate that it
has failed (and sometimes log the error if likely relevant).

in many cases, "assert" or similar can also be useful (in the case of
"clearly wrong behavior which should never occur during operation", for
example a required parameter being NULL, ...).

for example, if a required parameter is NULL or argument values are
invalid, very likely the caller has done something wrong, and it is
likely a good idea to trap into the debugger.

this isn't IMO a good strategy for "general issues" though, but more for
cases where "the caller has clearly done something wrong" or similar.

Regardless, you have the option of letting f log the incident, or not.

I actually do a fair amount of logging.

typically my apps will spit out a fair amount of information to logs as
part of their start-up process, and typically this will consist largely
of debugging-related messages.

this is fairly useful as, sadly, not everything can be easily tracked
down in a debugger (very often the case with bugs which result from
interactions between components, where often much of the effort may come
down to trying to track down just where exactly the bug actually is or
the state of the system in cases where it manifests).

But generally, e.g. when I'm going to call a C library function or
Windows API function that (as they typically do) has some ad hoc fault
indication + some error code scheme, then I usually wrap it in a
function or expression that throws a C++ exception. That's generally
more convenient even for local handling of the failure. And one main
reason is that it encapsulates and gets rid of all the myriad ad hoc
schemes for checking whether the function failed and for responding to
it -- it's a standardization and simplification.

yep, seems reasonable as such.


decided mostly to leave out descriptions of some of the hassles of
trying to use exception handling in C code via hand-rolled mechanisms
(it can be done, but isn't very pretty), or dealing with cross-language
error-handling (extra fun when the project is split between 3 or more
languages).


As shown by the various exception messages there are (at least) 4 ways
that "strtol" can fail.

I would speculate that in many programs using the "strtol" function
directly, not all failure paths are checked -- but the wrapper replaces
the sequence of four ad hoc checks with simple standard C++ exception
handling. Of course, with a C++11 conforming compiler there's little
need to call "strtol" because in C++11 iostreams do that for you (C++03
instead used the "scanf" family, with possible Undefined Behavior). But
I think it illustrates the case for wrapping in C++.

fair enough.

So, C = preference for codes, error handlers functions etc., and C++ =
preference for exceptions. But in some cases, as with e.g. calls across
binary module boundaries, you can't assume C++ exception support. Then
you have to design for the code to be callable as C, i.e. no exceptions.

yep.

it is better not to require a particular language for a library interface.

sometimes optional wrapper interfaces may make sense though, such as
wrapper classes or overloaded operators, ...

All that said, I'm primarily responding because I'm really curious about
where this great need for MECHANICAL RULES comes from?

If programming could be reduced to mechanical rules, if that was a good
idea, then, u know, it could be automated, and then you would not have
this problem of finding the rules because you wouldn't be programming:
it would be done by machine... So, instead of seeking mechanical rules
to be applied mindlessly, I suggest seeking up concrete EXAMPLES of
failure handling. Then apply INTELLIGENCE and understanding of concrete
situations that you face, and just strive to Keep Things Simple. ;-)

I actually have little idea where it comes from, but I have seen lots of
this in a number of language groups, namely people who believe that
"language X must be used this particular way", following certain little
rules (often trivial, sometimes arcane), and also that they represent
"authority" on "what everyone using the language does and believes".


sometimes, there are good "rules of thumb", but ultimately it comes down
to whether or not the rule will be beneficial in a given situation,
rather than it being something which must always be followed (even in
situations where it doesn't make sense or would do more harm than good).

although, sometimes there are edge cases, for example, "goto":
there is a rule to never use "goto";
then again, there are some potential edge cases where it could be
useful, and it seems disagreeable to ban a feature outright;
however, for code that is not already a mess, it is very rare to
actually have much need to use a "goto" to begin with (so, it seems more
like it is a symptom of spaghetti code, rather than the cause of said
spaghetti code).


many other cases appear to be similar, with people more often focusing
more on the symptoms of a problem, rather than on the cause of the
problem. ( they see the symptoms and the cause as one and the same? )


or such...
 
M

mike3

On 29.05.2012 06:15, mike3 wrote:
All that said, I'm primarily responding because I'm really curious about
where this great need for MECHANICAL RULES comes from?

If programming could be reduced to mechanical rules, if that was a good
idea, then, u know, it could be automated, and then you would not have
this problem of finding the rules because you wouldn't be programming:
it would be done by machine... So, instead of seeking mechanical rules
to be applied mindlessly, I suggest seeking up concrete EXAMPLES of
failure handling. Then apply INTELLIGENCE and understanding of concrete
situations that you face, and just strive to Keep Things Simple. ;-)

So where could I get examples of _well-written_, _well-designed_,
_smell-free_ error handling in a _non-trivial_ program?

And also, perhaps I'm not necessarily so interested in rigid rules as
to
understand better how to make "good" code.

A big problem is that I seem to find a lot of conflicting information.
Some say use exceptions, others say use codes, others say use
exceptions only when "exceptional", otherwise presumably use codes.
But codes have a number of problems of their own (see the thread
on comp.lang.c where I deal with C where there are no exceptions
and only codes). Which makes me want to use exceptions. And
indeed, some say that -- use exceptions. But then I get this thing
in my head saying "but maybe those people who say it should only
be used in 'exceptional' circumstances have a good point". And
then I'm once again confused. And then what "exceptional" means
is itself, apparently dependent on the speaker.

Would I be right to think the best thing to do here is just pick an
approach and see where it goes, don't bother worrying who's more
"right"? Is this just one of those things that simply does not *have*
a pat, objective answer, and so you have to do some picking and
choosing and seeing what happens?

And then I look at examples with other programs, and I see the
practices someone says "no" to being used! "NO" globals, there's
a global! And sometimes it's not even just one but a whole lot!
"NO" GOTOs, and oh my gosh what is that?! A GOTO!!!!! Keep
methods "under 20 lines", and then I see a lot of huge methods.
And it doesn't help when the tone I hear from the people and places
saying "no" is one of near-finality, like these things should only be
used in RARE circumstances.
 
B

Balog Pal

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

Simple guide is that you use return code if the immediate caller is supposed
to care about the failure details and act. While throw is for long-range
communication. Not surprizingly for some functions both make sense.
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.

Makes sense.
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?

Look for antipatterns.

If you see abundance of try blocks, especially catch after a single call,
the function would be better off with return code.

If you see return-code-football happening, like a row of
if ( (ret = Act()) < 0)
return ret;
you'd be better off throwing, and a catch where actual handling happens.

Certainly this applies to healthy, C++-style code, where objects take care
of themselves (see RAII), and no explicit management code is needed. If you
see free/delete/close... actions in the catch blocks and after those ifs,
fix that first.
Also, how exactly does one go about determining what is and is not
"exceptional"?

You issue a command and expect it to succeed under normal working
conditions. I.e. I expect that there's enough memory to complete the task,
that there's enough space on FS to write, TCP connection delivers, the valid
database operation carries out, I can open the files the program created,
or are there as part of the install.

If any of those fail, it's exception.

OTOH raw input form a user/outside world can be anything, so first it must
be checked/sanitized. Failure is properly expected.

However the decision is a practical matter. you balance good-looking code
and consider runtime penalties. Don't sweat on cases where you have no clear
pick.
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).).

Depends on what is asking. If your program code that should have obey the
bounds, then it is a completely different field, that of assert() and
terminate() due to detected bug.

If it's input from outsude, then you shall gate it, and have behavior
defined in the design.
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?

That is up to you to define. If you specify the bounds as precondition, then
you may leave the behavior undefined. (Or you may define it to something,
but it helps little outside a testing environment).
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".

Certainly the function is hosed. :) exception looks like the easy way out.
But that holds only locally. If the caller thought the bounds were okay, and
turned out wrong, who shall handle the exception and how?

OTOH you can define the function as 'best-effort', and allow blind calls.
Definig the behavior as you like, including to throw or return some default
ot NULL object. (consider a sparse matrix with unlimited size, that holds
only values for cells explicitly set, and for anything else returns 0.)
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;

:)

Exactly. The cheese of error handling is the HANDLING part, not emitting
the error via whatever means. Concentrate on that, and the rest will be
easy.

In a normal system that use exceptions the catch stes are pretty rare, and
most functions are exception-transparent.

The function that detects a problem condition is normally clueless on what
to do, and same goes for its immediate invoker... :)
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

This sounds quite fishy. You either handle the error or not -- there is
hardly place to be graceful.
(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.

It is.
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?

Why you think they shall be connected? Just use everything for its own
benefit.
 
I

Ian Collins

So where could I get examples of _well-written_, _well-designed_,
_smell-free_ error handling in a _non-trivial_ program?

And also, perhaps I'm not necessarily so interested in rigid rules as
to
understand better how to make "good" code.

A big problem is that I seem to find a lot of conflicting information.
Some say use exceptions, others say use codes, others say use
exceptions only when "exceptional", otherwise presumably use codes.

I don't think anyone advocates mixing styles. Pick one or the other.
But codes have a number of problems of their own (see the thread
on comp.lang.c where I deal with C where there are no exceptions
and only codes).

Which is why most modern languages have exceptions.
Which makes me want to use exceptions. And
indeed, some say that -- use exceptions. But then I get this thing
in my head saying "but maybe those people who say it should only
be used in 'exceptional' circumstances have a good point". And
then I'm once again confused. And then what "exceptional" means
is itself, apparently dependent on the speaker.

If you go down the exceptions route, your functions will either have a
void return or return a value. Your functions will do what they are
contracted to do and throw an exception if they are unable to meet their
obligations. That may involve the option of spitting some operations
into two calls (say does item X exist and get item X). The client code
can happily call the functions and move on. The error handling is not
mixed in with the programme logic, it is collected together in exception
handler(s). If that style suits you, follow it.

If you prefer to mix error handling with programme logic, use error
codes and make sure to check them!
Would I be right to think the best thing to do here is just pick an
approach and see where it goes, don't bother worrying who's more
"right"? Is this just one of those things that simply does not *have*
a pat, objective answer, and so you have to do some picking and
choosing and seeing what happens?

Yes, assuming a green field project. Otherwise use the "when in Rome"
approach.
And then I look at examples with other programs, and I see the
practices someone says "no" to being used! "NO" globals, there's
a global! And sometimes it's not even just one but a whole lot!
"NO" GOTOs, and oh my gosh what is that?! A GOTO!!!!! Keep
methods "under 20 lines", and then I see a lot of huge methods.
And it doesn't help when the tone I hear from the people and places
saying "no" is one of near-finality, like these things should only be
used in RARE circumstances.

Creating rules and ignoring them is a clear sign of a broken process.
If anyone were to find a goto in my code, I would be obliged to buy them
a very large quantity of beer.
 
B

Balog Pal

All that said, I'm primarily responding because I'm really curious about
Yeah.

So where could I get examples of _well-written_, _well-designed_,
_smell-free_ error handling in a _non-trivial_ program?

Why would you need examples?

K-PEX-ians would likely say that any inelligent being is well capable of
telling right from wrong -- you even demonstrated it in the initial message,
so all you lack is self-confidence. ;-)

You see the noise and repetition caused by mis-application of a method. So
just think the alternatives and chose the one that has least of those
problems.
And also, perhaps I'm not necessarily so interested in rigid rules as
to
understand better how to make "good" code.

Write alternatives and read them back. Ot show them for review.

And no, you can't have a general solution for the concrete problems. No
silver bullets. You must think alternatives for every particular case.
A big problem is that I seem to find a lot of conflicting information.

Just like the three blind guys go into "contradictions" describing the
elephant...
Some say use exceptions, others say use codes, others say use
exceptions only when "exceptional", otherwise presumably use codes.
But codes have a number of problems of their own (see the thread
on comp.lang.c where I deal with C where there are no exceptions
and only codes).

Heh, is there a point in that discussion? It should be vwell known, that you
can have only two kinds of C code: the incorrect and the unreadable.
Exactly due to the lack of sensible centralized error handling, and
auto-cleanup. So any code that actually checks the return codes (that in C
have no realistic good alternatives) will be infested with all the checks
and cleanup actions. To a level you can't see what should go on.
Which makes me want to use exceptions. And
indeed, some say that -- use exceptions. But then I get this thing
in my head saying "but maybe those people who say it should only
be used in 'exceptional' circumstances have a good point".

Did you try the 'five whys' method?

Sure they have some point. Dig out what it is, and you can decide whether it
applies to your case or not.
And
then I'm once again confused. And then what "exceptional" means
is itself, apparently dependent on the speaker.

Probably more dependent on the patricular situation. The same event can be
exceptional in one program and exceptional in another.

Would I be right to think the best thing to do here is just pick an
approach and see where it goes, don't bother worrying who's more
"right"?

Hell yes. ;-) The Master thought to tell the good tree by the good
fruits.
Is this just one of those things that simply does not *have*
a pat, objective answer, and so you have to do some picking and
choosing and seeing what happens?

IMO the stuff for which some objective answer exists is pretty rare.
And then I look at examples with other programs, and I see the
practices someone says "no" to being used! "NO" globals, there's
a global! And sometimes it's not even just one but a whole lot!
"NO" GOTOs, and oh my gosh what is that?! A GOTO!!!!! Keep
methods "under 20 lines", and then I see a lot of huge methods.
And it doesn't help when the tone I hear from the people and places
saying "no" is one of near-finality, like these things should only be
used in RARE circumstances.

Huh. Did you ever hear people saying that any guideline is only as good as
you understand its rationale?

I met a plenty of those "NO" guys, asked the 5 whys, most started to sweat
blood right at the first, or didn;t even understand what "why" means and if
he supposed to provide some answer.

Those you san send directly to <Censored> not passing GO and not collecting
$200.

OTOH look how true mentors work. Like HS+AA with the book 'C++ Coding
Standards'. For every item it is told why it's good, why bad, what are
exceptions, and provide a deal of references to more detailed explanation.
And you will find that those references have similar quality.
 
B

Balog Pal

So does this mean we should have an exception class defined for every
error code, so we can do that "conversion"?

Why would you use a *class* to represent a single value?

A single class OsException can very well have a member to hold the value of
errno (and another for GetLastError()) so covering all the values those
take.
 
B

Balog Pal

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.

A polite library that throws defines a hierarchy of exceptions and makes all
of them catch-able using a single root. And even that is supposed to be a
subclass of something likely present in the environment (std::exception,
CException if the library uses MFC, etc...) so they can be processed along
with others.

And catching exceptions after every call is hardly a good use -- catch them
collectively.
 
L

Luca Risolia

So where could I get examples of _well-written_, _well-designed_,
_smell-free_ error handling in a _non-trivial_ program?

Non-trivial programs tend to be a bad source of good examples.
Examples of ideal solutions to *non-trivial problems* are in good
textbooks, So take a good one and let it be your bible for some time.
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top