Necessity of multi-level error propogation

T

Tony

Is multi-level error propagation necessary outside of of constructors and
overloaded operators? (rhetorical, of course not). Doesn't it really just
boil down to this: constructors and overloaded operators require exceptions,
unless you realize that in your project not even those do, in which case you
can avoid using exceptions altogether (?).

Tony
 
A

Alf P. Steinbach

* Tony:
Is multi-level error propagation necessary outside of of constructors and
overloaded operators? (rhetorical, of course not).

The number of tails depends on the dog, but in general, when the otherwise 100%
meaningless "necessary" is interpreted as "of practical utility" : yes.

Doesn't it really just
boil down to this: constructors and overloaded operators require exceptions,
unless you realize that in your project not even those do, in which case you
can avoid using exceptions altogether (?).

No.

It's a good idea to try to avoid simplified mechanical (a.k.a. idiot's) rules.
If programming and design could be reduced to such rules then it would
presumably all have been automated by now. Instead we're required to /think/,
and that means think /all the time/, making informed and intentional decisions.


Cheers & hth.,

- Alf
 
T

Tony

Alf P. Steinbach said:
* Tony:

The number of tails depends on the dog, but in general, when the otherwise
100% meaningless "necessary" is interpreted as "of practical utility" :
yes.

You knew I disagreed with that before you even wrote it (?). :p Your "of
practical utility" is of reference to that which I have overcome. (OK, I
haven't, but I'm not sold on RAII and the ASSOCIATED COMPLEX MACHINERY it
introduces. C++ all about corner cases and what makes the GP language
concept, it's still just a concept IMO, seems pretty silly).

(See, you knew I had a point).

I don't think you know.
It's a good idea to try to avoid simplified mechanical (a.k.a. idiot's)
rules.

Then why did you suggest that? Are you an idiot?
If programming and design could be reduced to such rules then it would
presumably all have been automated by now.

No one stated a rule. I was talking about inventions (and perhaps the
politics of non-invention).
Instead we're required to /think/,

The important thing is to think on topic and not "how to make money". "Group
think" is decidely bad (or so I remember being taught and believing... umm,
knowing!).
and that means think /all the time/, making informed and intentional
decisions.

I agree. Horses designed by camels just don't work.

Tony
(Cheers!)
 
J

James Kanze

Is multi-level error propagation necessary outside of of
constructors and overloaded operators? (rhetorical, of course
not). Doesn't it really just boil down to this: constructors
and overloaded operators require exceptions, unless you
realize that in your project not even those do, in which case
you can avoid using exceptions altogether (?).

You can certainly avoid exceptions entirely. I've written lots
of C++ (and even more C) which didn't use them. On the other
hand, there are many cases where avoiding them results in more
complicated code, which is more difficult to maintain, and given
that all modern compilers (at least on general purpose machines)
implement them reasonably well, in most cases avoiding them
would be stupid and extremely unprofessional; it would mean not
using an effective tool available at your disposal (or in other
words, doing things the hard way). (There may be specific cases
where you'd have to avoid them, say on an embedded processor
with very, very little memory.)

(And now Jeff Schwab is going to get on my back because I've
used the word "stupid".)
 
T

Tony

Is multi-level error propagation necessary outside of of
constructors and overloaded operators? (rhetorical, of course
not). Doesn't it really just boil down to this: constructors
and overloaded operators require exceptions, unless you
realize that in your project not even those do, in which case
you can avoid using exceptions altogether (?).

You can certainly avoid exceptions entirely. I've written lots
of C++ (and even more C) which didn't use them. On the other
hand, there are many cases where avoiding them results in more
complicated code, which is more difficult to maintain, and given
that all modern compilers (at least on general purpose machines)
implement them reasonably well, in most cases avoiding them
would be stupid and extremely unprofessional; it would mean not
using an effective tool available at your disposal (or in other
words, doing things the hard way). (There may be specific cases
where you'd have to avoid them, say on an embedded processor
with very, very little memory.)

(And now Jeff Schwab is going to get on my back because I've
used the word "stupid".)"

In lieu of other techniques, avoiding exceptions may indeed be "stupid".
However, given robust replacement techniques, the opposite may be true:
using exceptions would be stupid.

I think I was pondering doing an alternative to exceptions on a
'substantial" project when I posted the OP and was hoping for more insight
as to where it would come back and bite me or haunt me.

Tony
 
T

Tony

Jeff Schwab said:
The thought did occur to me, but I've already said my piece. :) Aside
from the word "stupid," though, I agree with you here.

To the OP: It's almost impossible to really have a C++ program without
any exceptions at all. They're in the standard library, so you at least
have to be aware of them.

I don't use/am avoiding the standard library (and perhaps for now limiting
the kinds of software I build because of that (?)) other than to harvest
code "snippets" from it (I view the std library and C++ even as something to
abstract from via, you got it, "C++"!). I've gone to the extent (in the lab)
of replacing the initialization code and program entry point (as per trade
journal article) so that the standard library is not even initialized. It
works and reduces executable size significantly, but on my target platform,
size does not matter, so it may or may not be just an exercise. I ponder
"maybe not just an exercise" because bypassing initialization of the
standard library surely would mean that I have curbed any exceptions from
occuring. And apparently I don't have to go that far, because I can use the
compiler switch that "turns off" exceptions (to what degree, I have no
idea). What happens if I turn off exceptions and use the standard library is
unknown to me, but I surely would find that information useful in some way.

Tony
 
J

James Kanze

In lieu of other techniques, avoiding exceptions may indeed be
"stupid". However, given robust replacement techniques, the
opposite may be true: using exceptions would be stupid.

Using exceptions in cases where a different technique is
superior would be stupid. Systematically refusing to use them
for religious reasons is stupid. On any reasonably large
project, there'll be cases where exceptions are the most
appropriate solution (for starters, in constructors); banning
exceptions on a project wide basis is just plain stupid (as is
forcing their use for every single possible anomolous
condition).
I think I was pondering doing an alternative to exceptions on
a 'substantial" project when I posted the OP and was hoping
for more insight as to where it would come back and bite me or
haunt me.

Anytime you can't reasonable handle the error in the immediately
calling function. Also in constructors---the alternatives to
exceptions there can be very expensive in terms of development
and maintenance effort.
 
T

Tony

In lieu of other techniques, avoiding exceptions may indeed be
"stupid". However, given robust replacement techniques, the
opposite may be true: using exceptions would be stupid.

"Using exceptions in cases where a different technique is
superior would be stupid. Systematically refusing to use them
for religious reasons is stupid. On any reasonably large
project, there'll be cases where exceptions are the most
appropriate solution (for starters, in constructors); banning
exceptions on a project wide basis is just plain stupid (as is
forcing their use for every single possible anomolous
condition)."

I don't know what you mean by "religious reasons". I would hope that all
developers do things out of practicality. If the goal was to see what
alternatives develop (read, R&D), banning exception use would be not stupid,
but facilitating. "Double blind" experiment or similar.
I think I was pondering doing an alternative to exceptions on
a 'substantial" project when I posted the OP and was hoping
for more insight as to where it would come back and bite me or
haunt me.

"Anytime you can't reasonable handle the error in the immediately
calling function. "

I don't see that as a rule of thumb anymore since error codes can be
reliably propogated up the stack pretty easily without "jumping and
introducing alternative unwind mechanisms".

"Also in constructors---the alternatives to
exceptions there can be very expensive in terms of development
and maintenance effort."

Yes, constructors and overloaded operators MAY be an issue. But maybe that's
just a matter of coding style: if you choose to architect software using
RAII as a (or THE) design construct, then you will constantly be trying to
catch exceptions from constructors. It may be one of those "if it hurts when
you do that, don't do that" things.

Tony
 
L

Lionel B

[...]

"Anytime you can't reasonable handle the error in the immediately
calling function. "

I don't see that as a rule of thumb anymore since error codes can be
reliably propogated up the stack pretty easily without "jumping and
introducing alternative unwind mechanisms".

That was the whole point of James' comment, surely? Yes, "error codes can
be reliably propogated up the stack", but at the cost of checking error
codes all the way up the stack and introducing appropriate return paths...
in other words, implementing your own (clunky) unwind mechanism, when a
neat language-level mechanism (exceptions) already exists.
 
J

James Kanze

[...]
Anytime you can't reasonable handle the error in the immediately
calling function.
I don't see that as a rule of thumb anymore since error
codes can be reliably propogated up the stack pretty easily
without "jumping and introducing alternative unwind
mechanisms".
That was the whole point of James' comment, surely? Yes,
"error codes can be reliably propogated up the stack", but at
the cost of checking error codes all the way up the stack and
introducing appropriate return paths... in other words,
implementing your own (clunky) unwind mechanism, when a neat
language-level mechanism (exceptions) already exists.

That's more or less it. Obviously, we don't "need" exceptions;
I wrote code for close to 30 years without them. But using
them, at least in specific cases, means a lot less work, and
results in a lot more maintainable code. There are really two
cases where exceptions impose themselves:

-- Cases where the error will require abandoning a large block
of processing---in servers, for example, an error which will
require abandonning (and rolling back) the transaction, or
even breaking the connection. In this case, one throw and
one catch may replace literally thousands of if's, as well
as rendering the expression of the algorithms involved
clearer.

-- In constructors, where the alternative is often using zombie
states or some such. If the constructor throws, the object
isn't there, so you don't have to worry about it. Even if
constructors had return codes (and you can easily simulate
them, if you want, using out parameters), exceptions would
be preferable, because they don't leave an incomplete object
laying around.

There are probably other cases where they have practical
advantages, but these to are absolutes; the alternatives to
exceptions in these cases are very much more expensive, in terms
of development time and maintainability.
 
A

Annie Testes

Tony said:
[skip] If the goal was to see what
alternatives develop (read, R&D), banning exception use would be not stupid,
but facilitating. "Double blind" experiment or similar.

If it's for a research or teaching project, it can certainly be
interesting. If only to show how painful error management could be
in the good 'ol days of C :)

I don't see that as a rule of thumb anymore since error codes can be
reliably propogated up the stack pretty easily without "jumping and
introducing alternative unwind mechanisms".

Reliability:
One common problem in C, is that programers tend to forget to check
and/or
propagate errors. Since C++ has more functionalities, it can give
some help
that doesn't exist in C. You could start by looking at Alexandrescu's
mandatory error codes (http://www.ddj.com/cpp/184401917 [one third
down
the page])

Jumping:
In C, it's common to use early return from a function when
encountering a
error, which is a kind of jump. If the function needs to acquire a
resource
at the beginning and release it at the end, the idiomatic
implementation
uses gotos:

error_code func(void)
{
error_code res = no_error;
if (!acquire_resource) {
return error_out_of_resource;
}
if (foo()==failed) {
res = an_error_code;
goto cleanup;
}
if (bar()==failed) {
res = another_error_code;
goto cleanup;
}
cleanup:
release_resource();
return res;
}

Using a guard can probably simplify the code, but you would have to
keep the
hand-crafted test for resource acquisition, since you don't want the
guard
constructor to throw an exception. Something like the following can
be done:

error_code func()
{
if (!acquire_resource()) return error_out_of_resource;
Guard guard(release_resource);
if (!foo()) return an_error_code;
if (!bar()) return another_error_code;
return no_error;
}

As a comparison, in C++ with exceptions, you would have:

void func()
{
Guard guard(acquire_resource, release_resource); // may throw
foo(); // may throw
bar(); // may throw
}

Alternative unwind mechanisms

Even C has a stack unwinding mechanism, using setjmp and longjmp
(clunkier than exceptions, I think). And although I've never used it,
its mere existence makes me think that there are circumstances where
stack unwinding is clearly better than any alternative.

Yes, constructors and overloaded operators MAY be an issue. But maybe that's
just a matter of coding style: if you choose to architect software using
RAII as a (or THE) design construct, then you will constantly be trying to
catch exceptions from constructors. It may be one of those "if it hurts when
you do that, don't do that" things.

You can avoid exceptions in constructors by doing two-stage
initialization:
- the constructor doesn't execute any code that can fail, that means
that
the constructed object is often in an invalid state and therefore the
destructor needs to handle this special case.
- the class has an initialization function that can return an error
code.
Your code could look like this:

Foo *foo = new Foo();
if (!foo) { // not standard, but some compilers have a switch for
that
return error_out_of_memory;
}
error_code err = foo->init(x, y, z);
if (err != no_error) {
delete foo;
return err;
}
// go on with non-exceptional code path

Note that you've traded "constantly trying to catch exceptions" for
"constantly testing error code". OTOH, it may be possible to simplify
the code by using a fallible class (an example of a fallible class:
http://www.atnf.csiro.au/computing/...ore-0.4.0/doc/html/classcasa_1_1Fallible.html)
or by keeping an error code in the Foo class and doing an early return
in every member if the error is set.

As a comparison, in C++ with exceptions, you would have:

Foo *foo = new Foo(x, y, z); // may throw
// go on with non-exceptional code path


HTH
 
P

peter koch

The only know alternative to exceptions is return codes: comparing
these two alternatives, exceptions come out as the big winner in every
case where the errorhandling will not take place right after the
call.
[snipping a comment by James Kanze that looks as it came from you: you
really should setup your newsreader to perform proper quoting]
I don't know what you mean by "religious reasons". I would hope that all
developers do things out of practicality. If the goal was to see what
alternatives develop (read, R&D), banning exception use would be not stupid,
but facilitating. "Double blind" experiment or similar.


"Anytime you can't reasonable handle the error in the immediately
calling function. "

I don't see that as a rule of thumb anymore since error codes can be
reliably propogated up the stack pretty easily without "jumping and
introducing alternative unwind mechanisms".

This is a very fragile method, that takes considerable effort by the
programmers. It also heavily increases complexity of the program,
causing everything related to programming (reviewing, testing... )
much more difficult.
Yes, constructors and overloaded operators MAY be an issue. But maybe that's
just a matter of coding style: if you choose to architect software using
RAII as a (or THE) design construct, then you will constantly be trying to
catch exceptions from constructors. It may be one of those "if it hurts when
you do that, don't do that" things.

No you do not. When you use exceptions, you catch where you handle
error conditions, and nowhere else. Nothing hurts.

/Peter
 
J

James Kanze

On 11 Mar., 05:48, "Tony" <[email protected]> wrote:

[...]
The only know alternative to exceptions is return codes:
comparing these two alternatives, exceptions come out as the
big winner in every case where the errorhandling will not take
place right after the call.

For a very liberal meaning of "return code". You can use out
parameters, global variables (ever heard of errno?) or object
state (like in istream and ostream). Generally speaking,
however, everything but the object state works exactly like a
return value (except that there's usually no means of enforcing
that it is checked), sometimes with additional problems---I
can't think of a case where something like errno would be
appropriate. Using internal state for an error in a constructor
means that every function on the object must check it, and have
some defined behavior (no-op, etc.) in case of an error. This
is appropriate in cases like [io]stream, where the error can
introduce itself at any time, including after construction, so
you need the test anyway, but for most classes, it's just so
much extra overhead for the client, who has to be prepared to
deal with an object he cannot use.
 
A

Alf P. Steinbach

* Jeff Schwab:
errno isn't a global variable

errno is a global variable.

, it's a macro.

And yes, errno is required to be a macro.

In the first case 'errno' refers to a concept and/or bottom level implementation
of that concept.

In the second case 'errno' refers to a very limited tech detail view that few if
any find useful to know about, but the purpose of which is to provide the first
case's concept in a way such that people don't have to worry about the details.

On the system I'm using to
post this message, it maps to a function call.

Really?

The name 'errno' has to behave as a direct reference to a variable, so in C it
can at most map to an expression that dereferences the pointer result of a
function call (but it can there not map to a direct function call).

In C++ it can conceivably map directly to a function call, but it would be
rather silly to implement it differently in C++ and C.


Cheers & hth.,

- Alf (nitpicker-picker, for the occasion :) )
 
A

Alf P. Steinbach

* Jeff Schwab:
That was true in POSIX.1, but would be completely unworkable in a
multithreaded environment.

I'm sorry but that's a meaningless statement/assertion; it's contrary to readily
available fact.

'errno' refers to a macro, period.

Yes, 'errno' is a macro: nobody's contested that, so you're trying to (huff,
puff) blow down a wide open door here.

The "bottom level concept" typically
isn't a global variable,

Of necessity it must be a global variable, because that's what it is. :)

either, but some thread-local storage.

A global variable can be in tread-local storage, yes. Any variable in
tread-local storage is global, for any reasonable meaning of global in this
context. I noted else-thread, however, that today it seems you have severe
difficulties understanding that a word generally is meant to stand for its
contextually most sensible meaning instead of some least sensible meaning, which
is an issue that IMHO you really should look into (it starting to annoy).

The purpose of errno, as is often the case with macros, is to support
modern usage patterns, while conforming to ancient syntax.
Yes.



extern int * __error(void);
#define errno (*__error())


Right: it maps to a function call *and a dereference*.

That's markedly different from mapping to a function call.

This is a
markedly different case from your mistaken claim that errno must somehow
map to a global variable.

I'm sorry but I'm unable to see any single misconception that could make you
utter such a completely meaningless statement, so I'm assuming it's purely
argumentative: noise inserted with the intention of misleading some hypothetical
other reader than us two. Well that's just stupid. Get on the level, please, and
that means: stop micro-nit-picking and stop choosing inane meanings of words.

C++ compilers are not required to support C at all, so implementing the
two "differently" does not necessary come into play. Of course, it does
in every real-world implementation I've ever used.

Yes, it does matter in real world, and real world was what I referred to, while
in your reply now you chose to add reference to some purely academic POV.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* Jeff Schwab:

This is a newsgroup.

It's not a place to ask people to do things you want done.

If you have some argument, thebn make it: don't ask people to do things
for you.

Well, dang, notwithstanding that this is a newsgroup, did you have some argument
in mind, or not?

Now been waiting for *minutes*.

I think I'm reasonable.


Cheers,

- Alf
 
J

James Kanze

errno isn't a global variable, it's a macro. On the system
I'm using to post this message, it maps to a function call.

I was talking about the concept, not the actual implementation.
According to the C standard, errno is a "symbol" which expands
to a modifiable lvalue. (It may be a macro, or an indentifier.)
Historically, it was usually a global variable, and earlier
versions of Posix required that. A global variable doesn't work
very well in a multithreaded environment, however; I'm pretty
sure that Posix requires that it be distinct for each thread.
In the end, though, it is still a global variable, although
normally a thread local one.
 

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,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top