Error codes vs. exceptions

M

mike3

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

What are "K-PEX-ians"?
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.

What if one of the alternatives that looks good is something often
considered
"bad"? Like a global, or a goto?
Write alternatives and read them back. Ot show them for review.

You mean write the code and then read it to yourself? Write a method,
sniff it with your own nose?
And no, you can't have a general solution for the concrete problems. No
silver bullets. You must think alternatives for every particular case.

I didn't think so. I was looking more for just what needs to be
considered.
Just like the three blind guys go into "contradictions" describing the
elephant...

So does this mean the positions "use only exceptions" and "mix error
codes with exceptions" and "use only error codes" are not as
contradictory as they seem?
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.

Does this mean that C sucks?
Did you try the 'five whys' method?

Sure they have some point. Dig out what it is, and you can decide whetherit
applies to your case or not.

So then you should ask "why? why? why?" to ALL these rules -- use
only exceptions, use exceptions only when "exceptional" with error
codes
for everything else, use only error codes, never make a method more
than
X long (20 lines, one screen, etc.), never use a global, never use a
goto,
avoid singleton, etc.?
Probably more dependent on the patricular situation. The same event can be
exceptional in one program and exceptional in another.


Hell yes. ;-)    The Master thought to tell the good tree by the good
fruits.


IMO the stuff for which some objective answer exists is pretty rare.


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.

Isn't that a BIG problem if "most" fail to understand these reasons?
Does this mean I should get to work spending a lot of time memorizing
rationale? Where can I find detailed rationale for all these rules --
no long method,
no global, no goto, exceptions vs error codes, etc. so as to be able
to know
enough rationale to pass the "5 whys test"?
 
M

mike3

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.

Which ones would those be?
 
A

Adam Skutt

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

You're going to have to clarify what you mean by WFC. I don't think
it means what you think it means. If you mean the .NET runtime, then
you can't use that in C++, so it's somewhat irrelevant. C++/CLI is
not C++.
When you write your own library that will most often used with WFC, oftenwith
Qt and always with some STL -- how shall you expose your errors?

With an exception, inheriting from an STL one if you must inherit from
one (since it is 'always' used), though your problem honestly makes
little sense.
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)?

In general, if you have to catch std::exception or System::Exception
outside of the entry point of your program[1][2], you've done
something pretty wrong. I think you're trying to create artificial
problems.
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.

Surely, write a catch block? You seem to be confusing the response to
a condition with the condition itself, but I don't see anything here
that requires "special" handling or creates a problem. Nevermind that
I'm not quite sure how you'd mix the 3 libraries you mentioned in the
first place.
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?

Huh? The only way I can observe an exception from a given library is
if I'm actually calling functions within the library. As such,
needing to handle the exception can't possibly make me more dependent
on the library! You're going to need to provide an actual example of
what you're talking about.

If you're writing exception handlers to catch exceptions from
libraries you do not call (directly or indirectly), then you're doing
something completely and totally wrong.
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 crackand
refactor all errors before letting them further in a thin layer wrapping the
library calls your application uses.

No, the code that responds to an error condition really shouldn't care
how you received the condition initially: if you're going to log a
message in response to an error, the logging code doesn't care if you
got an exception, bungled about with return codes, or just made things
up. The same goes for displaying dialogs and just about every other
conceivable response.

The entire point of exception handling is that if you cannot (or need
not) respond to the condition, /you pretend that it does not exist/
[3]. If you're doing something else, then you're designing your code
entirely incorrectly. Such behavior is the height of
irresponsibility, because it is a fool's errand. C++ libraries need
not declare every exception they throw, so without walking every line
of code of every library you use (directly or indirectly), one cannot
even accomplish what you say should be done.
The code to capture error codes is simpler,
shorter and faster than that needed to capture exceptions.

I don't see how it can ever be less code than exception handling[4].
At best, it can be equal, and in practice, it must necessarily be more
because you're explicitly doing things that are done implicitly with
exception handling.
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.

Hardly. Just returning error codes doesn't suddenly let you mark
everything nothrow, due to the problem I mentioned above.
On top of this, following the code that only calls nothrow methods is much
easier which increases the programmer's productivity.

I fail to see how calling a method marked nothrow increases my
productivity at all. It doesn't reduce what I need to be worried or
concerned about unless the code actually provides the nothrow safety
guarantee, which is considerably difficult.

Merely not throwing exceptions is of very little benefit to the
programmer.
successful real-life applications and libraries (which is equivalent to saying
"applications and libraries of significant size") have to spend more timeon
reading and understanding code of others than on writing their own code.

Funny, I spend more time trying to figure out what was written in all
these technical papers I'm supposed to implement than looking at
anyone's source code. YMMV I guess.
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.

Unfortunately, the equation is changed, but based on what you've said
I think you did the calculation completely incorrectly in the first
place. Actually supporting your position with real code, which I
strongly encourage you to do, is going to be rather difficult.

Adam

[1] Or the entry point to a thread or similiar concurrency construct
[2] Though one should almost certainly 'catch(...)' in these contexts.
[3] Handling it here includes cleaning up resources and then kicking
the can down the road.
[4] The occasional syntax foible aside.
 
A

Adam Skutt

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

Just write code that uses the STL and iostreams w/ exceptions
enabled. That gives you a pretty decent model to follow, as C++ goes.
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.

That's because some people can't get over the fact that programming C
is not the best approach to everything, especially in languages other
than C.
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.

All that means is you shouldn't use exceptions as a value return
mechanism. You're entirely over thinking the problem. If a function
has a natural value to return, then it should return that value. If
it doesn't have a value to return and is only evaluated for side-
effects, it should return void. If the function cannot complete
whatever normal processing it was asked to do, then it should throw an
exception.

What is and isn't an exceptional condition is obvious based on the
situation at least 99/100 times, so you're wringing your hands about
nothing.

The hard part about exception handling is not deciding when to throw
(normally obvious) or what to throw (doesn't matter that much in the
grand scheme of things). The hard part is ensuring that the code you
write is safe when an exception is thrown: that it properly cleans up
after any resources it allocates and provides one of the three
exception-safety guarantees.
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"?

Yes, and No. Yes, because you're overthinking something that honestly
isn't that difficult all the time. No, because there is a "right"
answer here: use exceptions. The people supporting error codes in any
regard can't actually support their view, and when you take an example
and code them side-by-side, the winner is pretty apparent.

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.

The nice thing about this one is that is pretty easy to test: you can
write a moderate sized body of code both ways and decide for
yourself. Decided rationally and with code that otherwise follows
best practices, exceptions will win every time.

Adam
 
M

mike3

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.


Makes sense.


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.

But what if the error is not "exceptional", like an input parse error?
What happens if we were to use an exception because an error
has to propagate up several levels, but is not an "exceptional" error,
like a parse error?

Is it a good idea to default to exceptions for errors, and then if
after
you start actually using the code, it looks like an error code is more
appropriate, to use that instead?
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.

So does this mean the functions processing the input should return
error codes,
with all their messy glory?

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.

So does this mean to prefer an exception, since then we can do "x =
f() + said:
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... :)

Does this mean that we should prefer exceptions in that case, to allow
it to
propagate up to a higher level where something may be able to be done,
even
if the error is not "exceptional"? Whereas if we can handle it on-the-
spot, we
should use an error code? E.g.
This sounds quite fishy. You either handle the error or not -- there is
hardly place to be graceful.

I meant "if you have 10 calls to error-code-returning functions in
some
function, then _each and every one of those needs to be wrapped with
an error handler_". This significantly increases the length of the
original
function, and may obfuscate its purpose, by causing the code to be
dominated by checks/handlers. Not to mention if some of those handlers
function similarly, then we've got Duplicated Code(TM).

So then... "good idea to default to exceptions for errors, and then if
after
you start actually using the code, it looks like an error code is more
appropriate, use that instead"?
Why you think they shall be connected? Just use everything for its own
benefit.

So it's OK to keep a distinct set of exceptions that's different from
the list of
return codes?
 
I

Ian Collins

But what if the error is not "exceptional", like an input parse error?
What happens if we were to use an exception because an error
has to propagate up several levels, but is not an "exceptional" error,
like a parse error?

Well if the parser can't continue, it is exceptional. Both my XML and
JSON parsers make the reasonable assumption that the input documents are
well formed. If not, they throw an exception. In some cases the
exception is caught within the parser, augmented (say adding a line
number or the name of the malformed tag) and re-thrown. Given the
recursive nature of parsers, exceptions are an ideal choice.
So does this mean the functions processing the input should return
error codes, with all their messy glory?

There is no hard an fast rule.

If for example a function's job is to read an integer from a user, it
can keep prompting the user for the correct input until it gets it. If
it encounters an end of file condition it can't do its job so throw an
exception.
 
B

BGB

What are "K-PEX-ians"?


What if one of the alternatives that looks good is something often
considered
"bad"? Like a global, or a goto?

this can happen, but if one finds the best solution looking something
like a global or a goto, it may be better to look at whatever seems to
be leading to this "solution".


if one needs a goto because their function/method is a long winding
mess, then whether or not they should be using a goto is not really the
right question, but rather, the question may be better asked "what can I
do to break apart this function?".


and, sometimes, a global may be the right solution to a problem. at
other times, it may be a "solution" which comes back to bite later.

one may ask: why do I need this global?

You mean write the code and then read it to yourself? Write a method,
sniff it with your own nose?


I didn't think so. I was looking more for just what needs to be
considered.

this is hard to explain, and harder to get right.

some people seem to be going at it more like "I have a hammer and
everything is a nail", but rarely does this work out ideally.

So does this mean the positions "use only exceptions" and "mix error
codes with exceptions" and "use only error codes" are not as
contradictory as they seem?

probably.

the people were feeling up different parts of the elephant, and coming
up with different answers.

programming is sort of the same way, where the optimal solution to a
problem will depend highly on what is being done.

most contradictions of this sort really aren't, but are rather the same
issue as seen from different perspectives.


one error is not the same as another, either in terms of its nature, or
in terms of its relative costs and the relative costs of the ways to
address it.

to some degree, programming is a big game of cost-benefit analysis.

Does this mean that C sucks?

some people feel this way.


I say a lot depends on what one is looking for.

C is hardly pleasant, easy to use, or results in pretty code.
there might be other reasons to use it though, so a lot depends.

So then you should ask "why? why? why?" to ALL these rules -- use
only exceptions, use exceptions only when "exceptional" with error
codes
for everything else, use only error codes, never make a method more
than
X long (20 lines, one screen, etc.), never use a global, never use a
goto,
avoid singleton, etc.?


I once worried a lot about rules (although, in my case, it was worrying
more about the nature of ethics and morality).

ultimately, I noted a few things:
it all basically boils down to cost-benefit analysis;
not all cost-benefit is necessarily self-serving;
the line between helping oneself and helping others is nowhere near as
clearly defined as people make it out to be (there is heavy emphasis
placed on "helping oneself at the expense of others" vs "helping others
and asking nothing for oneself", but ultimately this may be itself, for
the most part, a false dichotomy, and "oneself vs others" is not really
asking the right question).


sadly, I don't know of any good way to explain this one.

Isn't that a BIG problem if "most" fail to understand these reasons?
Does this mean I should get to work spending a lot of time memorizing
rationale? Where can I find detailed rationale for all these rules --
no long method,
no global, no goto, exceptions vs error codes, etc. so as to be able
to know
enough rationale to pass the "5 whys test"?

this doesn't sound like a good strategy.


better would be not to try to memorize anything, but to try to
understand why these rules exist.

knowing words will ultimately not buy one a whole lot, if one doesn't
really understand what the words mean.


often, it is not about memorizing or knowing specific things, but
rather, about understanding why things are as they are in the first
place (how they came to be, and where they are going in the future).


yeah, this doesn't answer a whole lot, but I have little idea how to
explain what I am thinking here.
 
B

Balog Pal

What are "K-PEX-ians"?

A typo :( I meant K-PAX-ians. http://www.imdb.com/title/tt0272152/quotes
I just looked at the page, it has the quote right at the first spot. :)
What if one of the alternatives that looks good is something often
considered
"bad"? Like a global, or a goto?

Considered by who? As we are at it, do you actually believe the goto-bashing
morons?
In C, hosed of other tools, goto has mainstream use for the very topic we
discuss. Functions have double or one-and-a-half exit. The if( ) invocations
checking the status do a goto error_exit or goto cleanup.

Creating the best of what can be done for correctness, preserving the
maximum of readability. Certainly still far from the ideal.

And it is quite easy to put the alternatives side by side and watch
defenders of the "no goto" way to sweat explaining how the extra flags,
extra assignments, extra lines, duplicate code -- or the MACROs to mitigate
it should be considered better. You don't even need to ask the question
"now explain me, who is here really get confused by seeing that goto
cleanup or cleanup: -- and why we keep paying him?

Anyone can shout good or bad -- it has little/no info, skip directly to the
explanation part. If it's missing or speculative, well, guess what. ;-)
You mean write the code and then read it to yourself? Write a method,
sniff it with your own nose?
Yes.
I didn't think so. I was looking more for just what needs to be
considered.

Elswhere it was mentioned that writing exception-safe code is hard, maybe as
hard as correct MT. The last part is certainly not true, but there are some
gotchas, and you must be aware of them. Indeed it is easy to make some naive
mistakes that craete nasty bugs.

So before you jump on exceptions read at least the first too books of Herb
Sutter.

On the bright side we can state that a code that is not exception-safe and
needs adjusting is very-very likely wrong anyway, and needs the same
transformation for different reasons even without exceptions.

Basicly you need to look for code that has side effects avoid having too
many (mean more than 1 :) side effects in an expression.

So does this mean the positions "use only exceptions" and "mix error
codes with exceptions" and "use only error codes" are not as
contradictory as they seem?

Sure. The main guide is "do the right thing -- and for the right reasons".
May seem vague but works out in practice, and if you have a culture of code
reviews and team retrospectives (based on true openness) you even avoid
getting blinded by your own light. ;-)
Does this mean that C sucks?

Of course it does. What doesn't. Quoting Stroustrup: "The major cause of
complaints is C++ undoubted success. As someone remarked: There are only two
kinds of programming languages: those people always bitch about and those
nobody uses." It applies to C and many others.

C sucks for having very few tools, so you must spread complexity in the code
itself. Other languages suck because they have many tools, so the user must
learn them, use them correctly, and deal with the fact that the same thing
can be done n so many different ways.

So then you should ask "why? why? why?" to ALL these rules -- use
only exceptions, use exceptions only when "exceptional" with error
codes for everything else, use only error codes, never make a method more
than X long (20 lines, one screen, etc.), never use a global, never use a
goto, avoid singleton, etc.?

No, you ask one why on the rule, and keep asking why on the answers you get
recursively. Until you reach the roots. (Or discover there is no foundation
really just thin air.)
Isn't that a BIG problem if "most" fail to understand these reasons?

Sure it is. But that't the fact of life. Software creation (I'd not call it
engineering) is still in the wild west era. There are no quality controls on
any level -- especially on the consumer side that would drag the rest. Big
majority of the projects just fail to deliver or by delivery uses up 3 or
more times the budget and/or time. And the result is not pleasing.

I recall a fine red book from almost 30 years ago -- Ashton Tate's intro to
dBase III, where uncle Fred created the program to cover his fish-selling
shop. Using this shiny new tool, and reading this simple manual. And it was
a good book, I certainly could use it to write the programs just as
expected. But uncle Fread will not and can not. Ever since, no matter how
many shinier tools were created and how computers enetered the everyday
life.

Writing correct programs is just hard, and few can do it. The majority of
people involved in the industry can onjly provide stuff the "looks like
working" at best, or dragging down the overall project as baseline.

But shhhh, the Political Correctness cops say we are not supposed to reveal
that, and pretend that everyone is equally good ignoring all the
counter-evidence.

So I keep suggesting to ignore the loudness, and check only the rationales
given.

Does this mean I should get to work spending a lot of time memorizing
rationale?

Memorizing? No, a good rationale will just conquer your mind, and will pop
up as soon as you see something contradicting.

you need to read, study, understand the rationales, accept or reject them
for yourself. The rest just happens.
Where can I find detailed rationale for all these rules --
no long method,
no global, no goto, exceptions vs error codes, etc. so as to be able
to know
enough rationale to pass the "5 whys test"?

The Sutter/Alexandrescu book I already mentioned is a fine start.
 
R

Rui Maciel

mike3 said:
But what if the error is not "exceptional", like an input parse error?
What happens if we were to use an exception because an error
has to propagate up several levels, but is not an "exceptional" error,
like a parse error?

Is it a good idea to default to exceptions for errors, and then if
after
you start actually using the code, it looks like an error code is more
appropriate, to use that instead?

It really depends on what you define as an input parser error. Lexers are
designed to identify certain string patterns as specific tokens, while
identifying everything else as a very specific token; the "unknown token"
token. So, stumbling on an unknown token isn't necessarily an exceptional
event. The same applies to grammar errors. A set of tokens is either
matched by your grammar or it isn't. In some cases, a grammar might be
defined so that a specific sequence of tokens is recognized but interpreted
as an error. Either way, your parser still ends up in a recognized state,
and therefore these errors aren't exceptional situations.

So does this mean the functions processing the input should return
error codes, with all their messy glory?

That's up to whoever is in charge of designing the software. More
specifically, it must be decided which situation is expected and required to
express the control flow of your program and which situation is exceptional,
and therefore, for reasons such as clarity, it is benefitial to handle it
separately from the main control flow.

As an example, it's a good idea to write a lexer so that, when stumbling on
gibberish, it returns an error code signaling just that. By doing so, it is
possible to set the parser to handle the not so exceptional event of parsing
an ill-formed document, which might include the ability to throw a context-
dependent error message or even resume parsing. This wouldn't be easy or
simple to pull off if your lexer threw an exception when stumbling on
gibberish.


Rui Maciel
 
A

Adam Skutt

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 would love an example of this, because I've never seen such a
determination made, much less correctly.

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.

Expectation isn't enough to decide to not throw an exception. You
require both the expectation that the condition will happen and the
ability to respond to it. For a error code, you must be certain that
the proper place to respond is in the immediate caller.

The ability to make such a determination is extremely rare, including
for invalid input. Exceptions should be the normal response to
invalid input to a function, including to invalid input supplied by
the outside world.
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.

Perhaps, if you can determine it was programmer error. I'm not sure
the different behavior is really justified in the few cases where that
is possible.
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?

Perhaps no one, and that's perfectly fine. Just because an exception
is thrown doesn't mean it needs to be caught ever.
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.)

I don't know the value of an unlimited size matrix, nor how this would
work here.

Adam
 
B

Balog Pal

mike3 said:
Is it a good idea to default to exceptions for errors, and then if after
you start actually using the code, it looks like an error code is more
appropriate, to use that instead?

Yes. As I mentioned for some operations there's a need for both forms.
Fortuneately it's not hard to write converters in either direction, and then
clients can use the better-suited variant.
So does this mean the functions processing the input should return
error codes, with all their messy glory?

Don't confuse the situations and it's not that messy really.

In that layer you will have functions that return status. IsEmailValid()
shall not throw, but return bool, or some more detailed info on the
diagnosed problem. When you check the input you will call a ton of such
functions, and the caller will know how to act on discrepancy.

While those functions return "error code", it is not really that from the
function's perspective: it does all its work properly and that is the
result. It only becomes error code if the caller decides to not act, but
pass it upwards.
So does this mean to prefer an exception, since then we can do "x = f() +
<foo>"?

Yes, that is the main motivation. To separate the action logic and the
error-reaction logic. Not mix and tangle them together.
Does this mean that we should prefer exceptions in that case, to allow it
to
propagate up to a higher level where something may be able to be done, even
if the error is not "exceptional"? Whereas if we can handle it on-the-spot,
we
should use an error code? E.g.

By using the previously mentioned form you already admitted that the error
condition *is* exceptional.

If that invocation form is correct, it implies that
- involved operations are expected to succeed
- this spot has no interest in looking at error conditions

If the code expected some problem and had alternative actions in mind for
that condition, it would be there, wouldn't it?
So then... "good idea to default to exceptions for errors, and then if
after
you start actually using the code, it looks like an error code is more
appropriate, use that instead"?

Yes. Certainly don't forget to provide at least the basic exception
guarantee, and learn about tha Abrahams principles if you didn't yet.
So it's OK to keep a distinct set of exceptions that's different from
the list of return codes?

Those facilities serve some purpose. If you meet that purpose you're okay.
Does not matter how you do that.

In usual good code 95% of catch() blocks just do a conversion to some
different exception or a return code.

The rest minority that actually does something -- and it will just catch
*any* exception (with luck the common base class for all), and just call
..what() for a single string.

And that is more than enough. Top levels only care if stuff worked or not.
Rollback actions are issued via destructors (or simply lack of commit). The
inforlation on the problem trigger is carried in the exception object and
can present itself to a human-readable form so some actual intelligence,
outside the program can figure out what next.
 
N

Nobody

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

Assuming that the abundance of try blocks isn't just a case of the
programmer not understanding exceptions.
 
G

Guest

"The C++ Programming Language" by Stroustrup. There is a whole chapter
dedicated to exceptions.

and he discusses the reasons for the invention of exceptions.

I saw it most clearly when I reimplemented a simple socket program in Python where before it had been in C. The Python using exceptions was much clearer. The application was clearly separated from the error handling.
 
B

Balog Pal

I would love an example of this, because I've never seen such a
determination made, much less correctly.

MFC's CFile class has:

-ctor that takes filename, opens file and throws CFileException on a
problem.
-ctor that takes nothing and does not open the file
..Open() that takes filename, opens and return TRUE on success.

So where I expect the file to be there, I use the first form.

In other case the second. It's not at all uncommon to look for a file at
multiple different locations, all being optional. Or attempt to write a file
at some sensible location and fall back to ask the user if it can't be
created there.
The ability to make such a determination is extremely rare, including
for invalid input. Exceptions should be the normal response to
invalid input to a function, including to invalid input supplied by
the outside world.

That opens slippery slope for mixing program logic errors with environmental
factors outside our control.
Perhaps, if you can determine it was programmer error. I'm not sure
the different behavior is really justified in the few cases where that
is possible.

Come on! If a function has a precondition, then the programmer, the caller
is responsible to meet it.
If it is not met, it *is* a programmer error. Not cosmic rays or wrath of
God or anything.

And IMO systems based on contracts was beating those without anywhere in the
real world.
Perhaps no one, and that's perfectly fine. Just because an exception
is thrown doesn't mean it needs to be caught ever.

It is not fine. If the program derailed, it is in a state its creators
thought be impossible, any further action has fair chance to make thing even
worse. Unwinding the stack to some default habdler before exit IS further
action. Even if there is no handler, C++ does not specify whether stack
unwinding happens or not before terminate() gets called.

So throwing instead of halting is a fishy practice.

Also, in a program written in C++ that has any basic quality controls the
most likely cause hitting an assert failure is undefined behavior. And once
the behavior is undefined, do you think further will be good?
 
R

Rui Maciel

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

In some cases, both exceptions and error codes are adequate solutions.
Therefore, it isn't necessarily wrong or a bad idea to use either one in
those cases, and the decision to pick one tends to be a design decision.
Hence the apparently conflicting suggestions.

Personally, I see exceptions as a way to handle errors in a sequence point
other than the one immediately after where the errors are thrown. As a
downside, when you throw an exception you explicitly declare that you don't
know or even care which sequence point will be executed next. You trust
that the exception catching code does the right thing, and that the
program's execution will resume in a safe, innocuous sequence point.

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?

That sounds like a recipe for a mild disaster. After all, if you use a tool
without even thinking if it is the right one for your job then how do you
even know it is a good idea to use it?

A decent rule of thumb that helps see which solution is better suited is as
follows:
- if you are dealing with exceptional circumstances which can be omitted
from the control flow of your code without jeopardizing clarity or
readability (i.e., memory allocation errors, sanity checks failing in an
unexpected way, network connections breaking up, etc...) then exceptions may
be a good way to go.
- if, instead, you are dealing with expectable errors which directly
influence the control flow of your code to the point you can't express an
algorithm without explicitly covering them then returning error codes may be
a good way to go.

Other than this, it's a matter of understanding how exceptions and error
codes work, particularly their downsides, and make a design decision on
which one to pick to handle a particular error.


Rui Maciel
 
A

Adam Skutt

MFC's CFile class has:

-ctor that takes filename, opens file and throws CFileException on a
problem.
-ctor that takes nothing and does not open the file
.Open() that takes filename, opens and return TRUE on success.

So where I expect the file to be there, I use the first form.

In other case the second. It's not at all uncommon to look for a file at
multiple different locations, all being optional. Or attempt to write a file
at some sensible location and fall back to ask the user if it can't be
created there.

Yes, but that's hardly justification for the additional complications,
especially since there is no guarantee that "missing optional file"
will be handled in the caller, or that asking the user can be
performed in the caller. It's a dubious argument at best.
That opens slippery slope for mixing program logic errors with environmental
factors outside our control.

That slippery slope was opened before the application was even ever
started. How does a file open call distinguish between a string
supplied by the user and a constant within the program? It can't, so
it's a waste of time to try. The same applies to database connection
strings, usernames and passwords, and a whole host of other inputs
that are sometimes hardcoded into applications.
Perhaps, if you can determine it was programmer error. I'm not sure
the different behavior is really justified in the few cases where that
is possible.
Come on!  If a function has a precondition, then the programmer, the caller
is responsible to meet it.
If it is not met, it *is* a programmer error.  Not cosmic rays or wrathof
God or anything.

Sure, but the sort of things that were being discussed aren't ipso
facto preconditions of that sort. Asking for a non-existent tile on
the map might be a programming bug (e.g., an invalid position
calculation) or it might be invalid input (e.g., invalid input from a
client in a multiplayer game).

Again, even when you do know it must be a programming error, abrupt
termination is hardly a good policy. It's possible the bug can be
worked around by the user, even to simply save their work and quit.
Merely raising the exception achieves the desired response and leaves
space for better handling of programming bugs, compared to immediate
termination.
It is not fine. If the program derailed, it is in a state its creators
thought be impossible, any further action has fair chance to make thing even
worse.

Not all bugs yield undefined behavior, so this statement is just
false. If your code is exception transparent, then it doesn't matter
whether a function threw due to a programming error or invalid input
from the user or because the operation actually failed.

And if you can't write exception transparent code, then this whole
discussion is moot.
Unwinding the stack to some default habdler before exit IS further
action. Even if there is no handler, C++ does not specify whether stack
unwinding happens or not before terminate() gets called.
So?

Also, in a program written in C++ that has any basic quality controls the
most likely cause hitting an assert failure is undefined behavior. And once
the behavior is undefined, do you think further will be good?

I'm not sure I believe that would be the most likely cause. But even
it if were, trying to do something sensible and failing has the same
result as terminating on the spot. If you make things worse trying to
cleanup, then your cleanup code was broken to begin with. It was
going to make things worse even under defined failure conditions.

Adam
 
R

Rui Maciel

Adam said:
The entire point of exception handling is that if you cannot (or need
not) respond to the condition, you pretend that it does not exist.

A while ago I was working on an application that used Qt for the GUI and
Eigen for linear algebra. Long story short, under some circumstances Eigen
threw an exception and Qt caught it. And when Qt caught it, it terminated
the process.

So, if you follow your own advice then you better be prepared to deal with
its consequences.


Rui Maciel
 
A

Adam Skutt

{snip}
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.

No, the code that responds to an error condition really shouldn't care
how you received the condition initially: if you're going to log a
message in response to an error, the logging code doesn't care if you
got an exception, bungled about with return codes, or just made things
up.  The same goes for displaying dialogs and just about every other
conceivable response.
The entire point of exception handling is that if you cannot (or need
not) respond to the condition, /you pretend that it does not exist/
[3].  If you're doing something else, then you're designing your code
entirely incorrectly.  Such behavior is the height of
irresponsibility, because it is a fool's errand.  C++ libraries need
not declare every exception they throw,

  ...but they should, or at least declare that they throw or don't
throw.

They should declare what they know, but that might not be everything
that is possible to be thrown. Templates means that you have to work
with unknown types with unknown exception specifications. Yet, it's
perfectly possible to write code that works with the STL and other
libraries without this being a problem. So there's no reason to
believe that code should fully declare what exception types can be
thrown (generally)--the notion that this is unnecessary is baked into
the C++ standard library. Me, personally, I try to work with the
standard library, not against it.
  This is the problem I have with exception handling: you CANNOT
ignore exceptions. You must in some manner handle the possibility,
else your program ENDS!

Which is not a problem. I don't know why people think program
termination, especially in response to an error, is such a crime.
There's nothing inherently bad nor evil about it.
Handling minor, recoverable, errors with
throwing exceptions is like police shooting jaywalkers.

It is nothing of the sort. As I've asked many others, how exactly do
you determine whether an exception will be minor and/or recoverable
for any given application when you're writing a function, especially a
function in a general library? You can't. Even when you do know,
baking policy into such a function leads to brittle, unreusable, low
quality code. Just because it's a minor problem today does not mean
it will be a minor problem tomorrow.

Look at the C, POSIX, and Win32 APIs if you don't believe me: the
error codes returned by these functions describe the event that
occurred and nothing else. They generally make zero effort to
indicate whether a specific operation can be retried, or should be
retried[1], once the condition is raised. That distinction is left
entirely up to the caller to determine.
  Often, how you recover from an error depends on the specific error
information. If you "try" each individual function that might throw,
you might as well have error codes. The larger the "try" block, the
more difficult to isolate and repair/recover from the damage becomes.

If you're wrapping each individual function in a try block, you're
doing something very wrong. You're going to have to support the second
statement with actual code examples, as I don't understand what yo're
taking about. Correct exception handling means you don't care about
where an exception originated, but only about where you can handle
it. There's no need to "isolate" anything.
  So if I wind up using a library written by someone who throws an
exception for every incorrect condition, large or small, I have to
handle all of them or "throw the baby out with the bath water."

No, you only need to handle the ones you can trigger and respond to.
That rarely means all of them.
  Error conditions more often represent "that didn't work, I'll try
this" than "it's the end of the world!"

Utter nonsense. The return codes from std::fopen, as one of example
of many, may be fatal or not-fatal depending on the what the
application is doing. Some of them may also represent programming
errors, depending on what the application is doing. Just like you
can't say, "This exception represents a minor event", you can't
generally say the same thing about error codes!

Adam

[1] POSIX EINTR and EAGAIN being the most noticable exceptions.
However, not every situation where EAGAIN can be raised should be
automatically retried, so even it is not that simple.
 
A

Adam Skutt

A while ago I was working on an application that used Qt for the GUI and
Eigen for linear algebra.  Long story short, under some circumstances Eigen
threw an exception and Qt caught it.  And when Qt caught it, it terminated
the process.

So, if you follow your own advice then you better be prepared to deal with
its consequences.

Qt clearly says on its wrapper that it is not exception safe and has
said so since its inception AFAIK. Broken software doesn't really
impact my position any, though I suppose I should have mentioned
upfront that there's a depressing amount of software out there that
lacks exception safety.

Adam
 

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,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top