Why do some code bases don't use exceptions?

J

James Kanze

"dragan" ha scritto nel messaggionews:[email protected]...

[...]
12. they not have "the written form"
"if(a/b > c) u=z;"
if "a/b" throw one exception
in the plain text above;
there is not a single char in
"if(a/b > c) u=z;"
that show this chanches

That's probably because there is no such chance:).

But seriously, this is the one real problem with exceptions. And
the possibility of exceptions does require some additional
thought. But the problem has been addressed, and we do know
what has to be done.
13. the "exception header" not "know" the point of code
where is the problem. Instead returning the error-result of the
function the program know where is the error

That's the whole point of exceptions. They're for the sort of
problems where it doesn't matter where the problem occured; the
handling is the same. If you run out of memory processing a
request, for example, it doesn't matter where you were in the
processing when you ran out; you just abort the request (but not
the process) with an error message, and continue.
 
W

White Wolf

James said:
"dragan" ha scritto nel messaggio
[...]
12. they not have "the written form"
"if(a/b > c) u=z;"
if "a/b" throw one exception
in the plain text above;
there is not a single char in
"if(a/b > c) u=z;"
that show this chanches

That's probably because there is no such chance:).

But seriously, this is the one real problem with exceptions. And
the possibility of exceptions does require some additional
thought. But the problem has been addressed, and we do know
what has to be done.

Yeah, exceptions are a bitch that way. They force us to think and write
correct programs. :)

(One time people started to show me examples of where exceptions would
cause trouble in code. For 95% of those examples I could recreate the
problem by having Jane Summer add an if and a return statement in the
middle of that (already too complex and badly designed) function... And
summer trainees do exist, and they do add return statements. :)
That's the whole point of exceptions. They're for the sort of
problems where it doesn't matter where the problem occurred; the
handling is the same. If you run out of memory processing a
request, for example, it doesn't matter where you were in the
processing when you ran out; you just abort the request (but not
the process) with an error message, and continue.

One thing that confuses people is that they think that "handling" the
error means "fixing" the error, or "doing something and try again". It
may, but in most cases it won't be like that. Handling the error may
just mean what you have just said (even a bit less): stop doing what we
cannot do, meanwhile keep the system in a stable state, go on to some
task that we may be able to do.

Even sending an error message/log may be too much. Think of a system
that handles 400 SIP sessions per second as a border gateway. If
someone starts sending cr*p SIP messages and we end up logging the
details, our border gateway will create 400+ log entries per second. So
you should start bringing hard disks in wheel barrels to keep it running.

The job of a gateway is not to analyze or document, but to avert an
attack. We don't need to log anything. If the attack is ongoing, we
can analyze the packets of the failed sessions. If it stops, who cares.
(We will know there is an attack from the increased rejections and
perhaps the bandwidth.)

I guess that way of handling exceptions could be called "Nike from the
Opposite Universe": Just don't do it. ;)
 
J

James Kanze

James said:
"dragan" ha scritto nel
messaggionews:[email protected]...
[...]
But seriously, this is the one real problem with exceptions.
And the possibility of exceptions does require some
additional thought. But the problem has been addressed, and
we do know what has to be done.
Yeah, exceptions are a bitch that way. They force us to think
and write correct programs. :)

They introduce hidden flow paths which have to be considered
when evaluating program correctness. The fact that they don't
appear in the source code does increase the chance that they are
overlooked, and the fact that a lot of functions aren't
guaranteed to be no throw, although in fact they are, and if
return codes were used, they would still return void, increases
the actual workload, since without the nothrow guarantee, you
have to consider that they might throw.

How much extra effort and risk this entails has to be weighed
against the extra effort and risk of not using exceptions. Most
of the time, exceptions win.
 
P

peter koch

James said:
"dragan" ha scritto nel
messaggio    [...]
But seriously, this is the one real problem with exceptions.
And the possibility of exceptions does require some
additional thought.  But the problem has been addressed, and
we do know what has to be done.
Yeah, exceptions are a bitch that way.  They force us to think
and write correct programs. :)

They introduce hidden flow paths which have to be considered
when evaluating program correctness.  The fact that they don't
appear in the source code does increase the chance that they are
overlooked, and the fact that a lot of functions aren't
guaranteed to be no throw, although in fact they are, and if
return codes were used, they would still return void, increases
the actual workload, since without the nothrow guarantee, you
have to consider that they might throw.

Yes, but 99% of the time what is required is that your classes have
the basic exception guarantee - that you use RAII. The last one
percent you have to do some manual roll-back, but that code would have
to exist also in code not using exceptions.
How much extra effort and risk this entails has to be weighed
against the extra effort and risk of not using exceptions.  Most
of the time, exceptions win.

When not using exceptions, you more or less write the hidden error-
returning path explicitly in your code. In my experience, this often
gives a signicifand increase in source-code size and also obscures the
algorithm. This is a source of bugs, and the effort required to
explicite the path is normally much larger than the effort used to
write exception safe code.

/Peter
 
R

Richard

[Please do not mail me a copy of your followup]

peter koch <[email protected]> spake the secret code
When not using exceptions, you more or less write the hidden error-
returning path explicitly in your code. In my experience, this often
gives a signicifand increase in source-code size and also obscures the
algorithm. This is a source of bugs, and the effort required to
explicite the path is normally much larger than the effort used to
write exception safe code.

I agree with this -- manual error handling obscures the normal flow
of the code and makes it very hard to read, understand and debug.
 
J

James Kanze

James Kanze wrote:
"dragan" ha scritto nel
messaggio[...]
But seriously, this is the one real problem with
exceptions. And the possibility of exceptions does
require some additional thought. But the problem has
been addressed, and we do know what has to be done.
Yeah, exceptions are a bitch that way. They force us to
think and write correct programs. :)
They introduce hidden flow paths which have to be considered
when evaluating program correctness. The fact that they
don't appear in the source code does increase the chance
that they are overlooked, and the fact that a lot of
functions aren't guaranteed to be no throw, although in fact
they are, and if return codes were used, they would still
return void, increases the actual workload, since without
the nothrow guarantee, you have to consider that they might
throw.
Yes, but 99% of the time what is required is that your classes
have the basic exception guarantee - that you use RAII. The
last one percent you have to do some manual roll-back, but
that code would have to exist also in code not using
exceptions.

Perhaps the biggest argument against exceptions is that naive
programmers think that using RAII is sufficient for making
everything exception-safe:).

Seriously, there's more to it than that, but good transactional
semantics do go a long way. And transactional semantics are a
fairly well studied field; historically, it's not been usual to
apply them to analysing program correctness, but there's no
reason why it can't be done. It does increase the work
somewhat, but so does adding tons of additional if's to check
error conditions that you can't treat immediately either.
When not using exceptions, you more or less write the hidden
error-returning path explicitly in your code.

Exactly. Explicitly, so you see the paths, and don't forget to
analyse them for correctness as well.
In my experience, this often gives a signicifand increase in
source-code size and also obscures the algorithm.

And that's the down-side. It's a trade-off. If the error has
to be handled immediately anyway, there's not really any
additional code (an if on one hand, a try block on the other),
and the hidden paths cost more, so you use a return code. If
the error can't be handled until considerably further up the
call stack, adding if's in every intermediate function does have
significant cost, which usually outweighs the cost of having to
consider the hidden flow paths. At least if you can count on
no-throw guarantees for enough fundamental operations to ensure
transactional integrity.
This is a source of bugs, and the effort required to explicite
the path is normally much larger than the effort used to write
exception safe code.

Only if the error handling code isn't in the function where you
would have to write the explicit if's.
 
D

dragan

James said:
Even within a single application, different types of errors will
require different types of handling.

But that was my point: "one and only" mechanism is the "looking for the
silver bullet" approach.
For that matter, the same
type of error may require different handling in different
contexts: a write error in a log file should probably be
ignored; a write error in the program output (e.g. when writing
the object file in a compiler) should probably result in the
program terminating with an error status (after clean-up---I
can't think of any case where a write error should result in an
abort).


Which is what I said. Most of the time, aborting is the
appropriate reaction,

Reaction to what is the question. You must have something(s) specific in
mind.
and it is the obvious choice for a default
action,

Along with logging, backtracing, notification, perhaps restarting from
checkpoint, maybe rollback, maybe switching to redundant system 3...
Application-specific. Perhaps the only place abort is appropriate is in
language newsgroups! ;)
but I'm well aware that there are exceptions: game
programs, for example, and possibly light weight GUI client
code.

I don't think anyone has reasonably argued that exceptions are
an "error managment strategy". First, as you say, they are a
just a mechanism---a tool to implement a strategy, and not a
strategy. And second, they only address one aspect of error
management: reporting.

They don't do that at all. Exceptions are an error propogation mechanism in
C++, an probably best to use sparingly for places where local "handling" is
not possible (constructors, for one) or not appropriate (independently
developed libraries). Reporting comes after exceptions have done their part.
Error management involves three aspects:
detection, reporting and handling.

There is also: error definition & categorization and propogation. So I see
at least 5 things. If I ponder a bit more here, I may come up with a few
more things. I do know that I wouldn't call simply
detection/handling/reporting "error management" though, and that's not what
I meant when I used the terms. Documentation, communication and enforcement
of the prescribed or chosen strategies and patterns are a few more (see, I
came up with a few more in 1 minute). "Error management" as simply
detection/handling/reporting? Nah. No way.
Exceptions don't help in
detection, nor in handling. They just simplify reporting when
the error must be handled far up the call stack.

That's propogation, not reporting.
(Which means
that they are of no use when the error must be handled
immediately.)

Catch = handle error
I didn't elevate anything. I'm just describing what exception
specifications do.

I thought they were just documentation like precondition documentation.
It is. Since the standard says it is. A function with an
exception specification "throw (std::bad_alloc)" may not exit by
any exception other than std::bad_alloc or an exception which
derives from std::bad_alloc. And the standard is authoritive.

Whether such a "contract" is practically useful is another
issue.

That's why I hinting it was not authoritive. Bad choice of word (even the
way I speeled it!)
In practice, the only contract expressible by exception
specifications which I've found useful is "throw()". In
otherwords, that the function will not exit by an exception,
period. Without it, you can't really write exception safe code.


I'm having difficulty parsing what you're trying to say. But
programming by contract certainly hasn't failed, and is still
considered a good thing in most circles. As for exception
specifications, they're just another part of the contract. So
one can't say that they've failed.

Do you always use exception specifications? Do you people who never use
them?
What one can say is that the
contract they express is not all that useful

That's what I was hinting at, but not that I'm a one to discuss such C++
advanced topic.
(with the exception
of an empty exception specification---a no-throw guarantee).

Now exception (error) guarantees I can relate to: weak, basic, strong,
no-throw.
I didn't write the definition of exception specifications. It's
in the standard.

I was suggesting that you were maybe pontificating on purpose more far than
necessary from the practical.
I didn't write that, so I can't be sure, but a priori, an
"unexpected exception" is one that the programmer didn't expect;
that he wasn't prepared to handle.

I was thinking more from the detection level rather than
the-user-of-a-library level. Even if he didn't actually handle it and
because C++ default-handle it, it becomes "expected". IOTW,
"expected/unexpected" is more for discussion of how the C++ exception
mechanisms were designed: no exception goes unhandled.
 
D

dragan

James said:
I think you misunderstood my statement. I explicitly said "Just
a linguistic nit". All I disagreed with was his use of one
particular word.

Me too.
And that use, while not formally correct, is
quite idiomatic in English: you'll quite often hear "an
unprecedented amount of X" as an exagerated expression of "a lot
of X".

I was pointing that out because he was using it to bash the other guy for
doing something similar.
I don't think any amount of misconceptions would be
"unprecedented", given the number of sites on the Web by authors
who clearly don't understand what they're talking about. But
the site in question clearly falls into the category of sites
pontificating on subjects which the authors don't know very
well, if at all.

I thought some of the things were fine for a NEW language, but not for C++.
A lot of the material there is over my head though.
 
D

dragan

James said:
"dragan" ha scritto nel
messaggio
[...]
12. they not have "the written form"
"if(a/b > c) u=z;"
if "a/b" throw one exception
in the plain text above;
there is not a single char in
"if(a/b > c) u=z;"
that show this chanches

That's probably because there is no such chance:).

But seriously, this is the one real problem with exceptions. And
the possibility of exceptions does require some additional
thought. But the problem has been addressed, and we do know
what has to be done.
13. the "exception header" not "know" the point of code
where is the problem. Instead returning the error-result of the
function the program know where is the error

That's the whole point of exceptions. They're for the sort of
problems where it doesn't matter where the problem occured; the
handling is the same. If you run out of memory processing a
request, for example, it doesn't matter where you were in the
processing when you ran out; you just abort the request (but not
the process) with an error message, and continue.

You seem to be big on aborting. A very valid pattern is fixing the problem
and resuming. Some version of Windows expands the stack that way: a
violation occurs when trying to push beyond the current stack frame and the
system catches the error, expands the stack by 4k and continues processing.
(Not to bring up "termination vs. resumption" semantics, but not trying to
curb such discussion either. I'll just lurk and learn something). :)
 
D

dragan

James said:
James said:
"dragan" ha scritto nel
messaggio
[...]
But seriously, this is the one real problem with exceptions.
And the possibility of exceptions does require some
additional thought. But the problem has been addressed, and
we do know what has to be done.
Yeah, exceptions are a bitch that way. They force us to think
and write correct programs. :)

They introduce hidden flow paths which have to be considered
when evaluating program correctness. The fact that they don't
appear in the source code does increase the chance that they are
overlooked, and the fact that a lot of functions aren't
guaranteed to be no throw, although in fact they are, and if
return codes were used, they would still return void, increases
the actual workload, since without the nothrow guarantee, you
have to consider that they might throw.

How much extra effort and risk this entails has to be weighed
against the extra effort and risk of not using exceptions.
Most of the time, exceptions win.

Unless you are Google!?
 
D

dragan

peter said:
James Kanze wrote:
"dragan" ha scritto nel
messaggio[...]
But seriously, this is the one real problem with exceptions.
And the possibility of exceptions does require some
additional thought. But the problem has been addressed, and
we do know what has to be done.
Yeah, exceptions are a bitch that way. They force us to think
and write correct programs. :)

They introduce hidden flow paths which have to be considered
when evaluating program correctness. The fact that they don't
appear in the source code does increase the chance that they are
overlooked, and the fact that a lot of functions aren't
guaranteed to be no throw, although in fact they are, and if
return codes were used, they would still return void, increases
the actual workload, since without the nothrow guarantee, you
have to consider that they might throw.

Yes, but 99% of the time what is required is that your classes have
the basic exception guarantee - that you use RAII. The last one
percent you have to do some manual roll-back, but that code would have
to exist also in code not using exceptions.
How much extra effort and risk this entails has to be weighed
against the extra effort and risk of not using exceptions. Most
of the time, exceptions win.

When not using exceptions, you more or less write the hidden error-
returning path explicitly in your code. In my experience, this often
gives a signicifand increase in source-code size

Can you give some numbers?
and also obscures the
algorithm.

I don't see why. Hide the details with macros.
This is a source of bugs,

Yes, probably, without any formalism such as macros. I guess you could go a
step further and write a preprocessor do do some instrumentation for you
also.
and the effort required to
explicite the path is normally much larger than the effort used to
write exception safe code.

I think that would be the same or maybe harder with exceptions because of
the interactions with other C++ stuff (not that I can name that other stuff
though). Ensuring cleanup and RAII and call order and the like is an
on-going thing no matter what your EH strategies are.
 
P

peter koch

Unless you are Google!?- Skjul tekst i anførselstegn -

I believe what we are discussing now is "Google open source" not
Googles own software, which I don't know.


/Peter
 
P

peter koch

Can you give some numbers?

Not any exact ones, but I have been working in places where exceptions
were not used (due to some code being quite old and no one caring
about fixing). Code there typically looked something like:

int func(parm p,std::string &result)
{
std::string s;
int error;

result = func_1(parm,s);
if (error != OK)
{
return error;
}
error = func_2(s);
if (error != OK)
{
return error;
}
result = s;
return OK;
}

instead of the much simpler

std::string func(parm)
{
return func_2(func_1(parm));
}

This example is a bit exaggerated, as the function body does not do
very much, but it not atypical. One side effect of this style was that
functions typically returned a status, making calling the functions
more complicated. My guess is that the code length was at least
doubled this way. The above function has a 10-fold increase in lines
(disregarding braces), and it is not that easy to figure out what is
going on.
I don't see why. Hide the details with macros.

First that would require you to use macroes, which can lead to more
errors. Secondly: How would you hide the details in the code above?
Yes, probably, without any formalism such as macros. I guess you could go a
step further and write a preprocessor do do some instrumentation for you
also.

Yes. You could also use another language. If you get so far out that
you need to write a preprocessor that proposition might acutally be
worth following.
I think that would be the same or maybe harder with exceptions because of
the interactions with other C++ stuff (not that I can name that other stuff
though). Ensuring cleanup and RAII and call order and the like is an
on-going thing no matter what your EH strategies are.

As you, I see no interaction with other C++ stuff. Exceptions fit
perfectly with C++.

/Peter
 
A

Alf P. Steinbach

* peter koch:
Not any exact ones, but I have been working in places where exceptions
were not used (due to some code being quite old and no one caring
about fixing). Code there typically looked something like:

int func(parm p,std::string &result)
{
std::string s;
int error;

result = func_1(parm,s);
if (error != OK)
{
return error;
}
error = func_2(s);
if (error != OK)
{
return error;
}
result = s;
return OK;
}

instead of the much simpler

std::string func(parm)
{
return func_2(func_1(parm));
}

He he :)

Thank you.

I don't think I've ever seen a more clear example.


Cheers,

- Alf

PS: Btw., the shop should have used s.swap( result ). ;-)
 
R

Richard

[Please do not mail me a copy of your followup]

peter koch <[email protected]> spake the secret code
int func(parm p,std::string &result)
{
std::string s;
int error;

result = func_1(parm,s);
if (error != OK)
{
return error;
}
error = func_2(s);
if (error != OK)
{
return error;
}
result = s;
return OK;
}

instead of the much simpler

std::string func(parm)
{
return func_2(func_1(parm));
}

This sort of code is profusely present in code that uses COM because
every method on a COM interface typically returns an HRESULT status
code that you should check.

There are three ways I've seen people deal with such error codes:
- ignore them and pretend errors never happen (bad code)
- inline handling as above (hard to read code)
- map HRESULTs to exceptions and handle them at the appropriate
boundaries (throwing a C++ exception is undefined when implementing
a COM object, so you have to catch and bubble out HRESULTs)

The latter is the approach I have been teaching for almost 10+ years
now and it dramatically simplifies writing and understanding such
code.
 
J

James Kanze

But that was my point: "one and only" mechanism is the
"looking for the silver bullet" approach.

So we agree. (On that, at least.)
Reaction to what is the question. You must have something(s)
specific in mind.

When you detect a coding error (a violation of a precondition,
for example), aborting is *usually* the most appropriate
reaction. Not aborting should only be done in explicit cases,
where you understand the issues and are prepared to cope with
them.
Along with logging, backtracing, notification, perhaps
restarting from checkpoint, maybe rollback, maybe switching to
redundant system 3... Application-specific. Perhaps the only
place abort is appropriate is in language newsgroups! ;)

Abort is generally the most effective means fo switching to the
backup system. It's the generally accepted means of reacting to
software errors. More generally, if a program is doing the
wrong thing, it generally should be stopped as quickly as
possible, so that it doesn't do more of the wrong thing.
They don't do that at all. Exceptions are an error propogation
mechanism in C++,

Error propagation, error reporting: same thing, really.
Propagation is probably the better word, though; it just slipped
my mind.
an probably best to use sparingly for places where local
"handling" is not possible (constructors, for one) or not
appropriate (independently developed libraries).
Exactly.

Reporting comes after exceptions have done their part.

I think we're talking about different things. I was talking
about "reporting" the error to the location in the code where it
would be handled.
There is also: error definition & categorization and propogation.

Propagation is reporting, at least in the sense I was using the
word. Categorization is probably part of detection.
So I see at least 5 things. If I ponder a bit more here, I may
come up with a few more things.

You can certainly define it a lot finer, and there's often a lot
in each of those words. My basic idea was that you have to
think of errors in three contexts: where you're going to detect
the error (e.g. how, what type of error, etc.), where you're
going to treat it (log it, retry, etc.), and in between, where
you have to propagate it from where it was detected to where it
is to be handled.
I do know that I wouldn't call simply
detection/handling/reporting "error management" though, and
that's not what I meant when I used the terms. Documentation,
communication and enforcement of the prescribed or chosen
strategies and patterns are a few more (see, I came up with a
few more in 1 minute). "Error management" as simply
detection/handling/reporting? Nah. No way.

At the coding level:). I totally agree, my categorization
doesn't cover things like documentation and communication (to
other programmers), and they are very important.
That's propogation, not reporting.

Two words, same thing.
Catch = handle error

Yes, but having to write a try block, then a catch statement, is
more complicated than an if, if you want to process the error
immediately. You can use an exception, but it's about like
pealing a grape with a butcher's cleaver.
 
A

Alf P. Steinbach

* James Kanze:
Yes, but having to write a try block, then a catch statement, is
more complicated than an if, if you want to process the error
immediately. You can use an exception, but it's about like
pealing a grape with a butcher's cleaver.

Off the cuff,

#define CATCHX( result, f, args ) \
do { \
try { \
result = f args; \
} catch( std::exception const& x ) { \
result.set_x( x ); \
} \
} while( false )

Cheers & hth.,


- Alf
 
J

James Kanze

I don't really understand why the violation check's being done
at runtime rather than compile time (the way checked
exceptions in Java work) - the "what should happen if an
unexpected exception is thrown at runtime?" question is fair
enough, but why does it get to that point in the first place?
Is it difficult/impossible to do the check at compile time in
C++? Or is the issue that it would break a lot of old code
where the functions don't have exception specifications?

There are (I think) several reasons. One obvious one is that
that if you don't specify anything, the compiler will assume
that a function can throw anything, so you'd end up needing a
lot of otherwise useless try blocks with legacy code (since the
code doesn't declare that it can't throw, but it doesn't in fact
ever throw, and you know that). The other is the IMHO misguided
theory that it would require the programmer to provide
additional runtime checks. If, for example, you have a sqrt
function with throws if passed a negative value, and you write
something like:

double
checked_sqrt(double in) throw()
{
return in < 0.0 ? 0.0 : sqrt(in);
}

you'd need a try block to tell the compiler that you're not
going to allow any exceptions to escape. (As I said, I don't
actually agree with this reasoning. But it's a reason I've
heard cited.)
 

Ask a Question

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

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

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,161
Latest member
GertrudeMa
Top