Understanding Assert and Exceptions

P

Phlip

mlimber said:
Sure. But my point was that there are a good number of circumstances
where unit tests are simply not feasible (embedded systems is one,
legacy code with no existing unit tests is another) but where
exceptions and assertions can and should still be used.

I suspect a mis-alignment here.

I meant that tests, exceptions, and assertions are a three-legged stool. I
think you mean that tests can absolve the need for some of them. Maybe. You
are correct that's the fuzzier topic!
 
D

Duane Hebert

red floyd said:
If an exception is uncaught, eventually terminate() is called, causing
your program to drop dead.

Well that's my point. Saying that with an exception
you only need:

perform_transaction();

is only true if it's OK for your program to
terminate. Seems hard to grasp how failure
to perform a transaction should do that.

Normally you're going to have
to write a try/catch block around it. In that
case, it's no "cleaner" than the if block IMO.
 
D

Duane Hebert

Julián Albo said:
The point is that at some point I, or some other programmer that use the
function, can catch the exception. Or just let the program terminate, if
it's a simple command line tool used for people that knows how is written.

And so then the exception example is not
so elegant. I would still have it return
a bool. If you want to bail at that point,
you can always let the caller throw if there's
no other way out. But how can you know that
from inside of perform_transaction()?
I don't think embracing exceptions
for error indication is the correct thing to do.
Feel free to have your own opinion <g>
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Duane said:
And so then the exception example is not so elegant.

Don't see the point.
I would still have it return a bool.

Just do it. This is not a "Always do it that way" thing.
I don't think embracing exceptions for error indication is the correct
thing to do.

I don't think so. I also don't think that return error codes is "the
correct" thing. There are no one only correct way.
 
G

Gavin Deane

Duane said:
Well that's my point. Saying that with an exception
you only need:

perform_transaction();

is only true if it's OK for your program to
terminate.

No. It's also true if the error handling code is at some level above
the code that calls perform_transaction.
Seems hard to grasp how failure
to perform a transaction should do that.

Normally you're going to have
to write a try/catch block around it.

Yes, at some level, but not necessarily the same level as the call to
perform_transaction.
In that
case, it's no "cleaner" than the if block IMO.

A try-catch block is only no cleaner than an if-else block if the error
handling happens at the same level as the call to perform_transaction.
If the error handling happens further up the call stack then, with an
exception, all the intermediate layers can ignore the failure and
remain unchanged. Whereas, if perform_transaction returns an error code
or flag, every intermediate layer must have a return code and maybe an
if-else block added just to propogate the error state up to the level
that needs to know about it, which is definitely less clean than the
exception solution.

Gavin Deane
 
M

mlimber

Gavin said:
A try-catch block is only no cleaner than an if-else block if the error
handling happens at the same level as the call to perform_transaction.
If the error handling happens further up the call stack then, with an
exception, all the intermediate layers can ignore the failure and
remain unchanged. Whereas, if perform_transaction returns an error code
or flag, every intermediate layer must have a return code and maybe an
if-else block added just to propogate the error state up to the level
that needs to know about it, which is definitely less clean than the
exception solution.

In other words:

int f1();
int f2();
int f3();
int f4();
int f5();
int f6();

int g1()
{
int rc = f1();
if( 0 != rc )
{
return rc;
}

rc = f2();
if( 0 != rc )
{
return rc;
}

rc = f3();
if( 0 != rc )
{
return rc;
}
return 0;
}

int g2()
{
int rc = f4();
if( 0 != rc )
{
return rc;
}

rc = f5();
if( 0 != rc )
{
return rc;
}

rc = f6();
if( 0 != rc )
{
return rc;
}
return 0;
}

int h()
{
int rc = g1();
if( 0 != rc )
{
// Do some error handling
return rc;
}

rc = g2();
if( 0 != rc )
{
// Do some error handling
return rc;
}
return 0;
}

Vs.

void f1();
void f2();
void f3();
void f4();
void f5();
void f6();

void g1()
{
f1();
f2();
f3();
}

void g2()
{
f4();
f5();
f6();
}

void h()
{
try
{
g1();
g2();
}
catch( const std::exception& e ) // and/or custom exception classes
{
// Do some error handling
}
}

While both leave the error handling proper to a higher level [viz., in
h()], the second version represents the program flow much more clearly
thanks to exceptions.

Cheers! --M
 
M

mlimber

Phlip said:
I suspect a mis-alignment here.

I meant that tests, exceptions, and assertions are a three-legged stool. I
think you mean that tests can absolve the need for some of them. Maybe. You
are correct that's the fuzzier topic!

It sounded to me like you were saying that using assertions and
exceptions is pointless (like a two-legged stool) unless there are unit
tests to back them up and test them out thoroughly. I'm saying that
sometimes it is not practical to build such a unit test suite but that
even in those case, exceptions and assertions can still be of great
utility.

Cheers! --M
 
M

mlimber

My conclusion: throwing an exception is still better than assert, for
you can always print a user friendly message to the screen.
[...]
Now, if you happen to have any exceptional situations and you deside to
throw an exception, this is more an excuse for poor programming, I
think. Again, what can one do about an integer overflow? Or a wrong
static_cast?
[...]
What do you think?

Sutter and Alexandrescu in _C++ Coding Standards_ address error
handling policy in more detail than we will likely do here (but, for my
taste, even more detail than theirs would be useful!). Some key
summaries are:

Item 68: Assert liberally to document internal assumptions and
invariants. Be assertive! use assert or an equivalent liberally to
document assumptions internal to a module (i.e., where the caller and
callee are maintained by the same person or team) that must always be
true and otherwise represent programming errors (e.g., violations of a
function's postconditions detected by the caller of the function).

Item 70: Distinguish between errors and non-errors. A breach of
contract is an error: A function is a unit of work. Thus, failures
should be viewed as errors or otherwise based on their impact on
functions. Within a function f, a failure is an error if and only if it
violates one of f's preconditions or prevents f from meeting any of its
callees' preconditions, achieving any of f's own postconditions, or
reestablishing any invariant that f shares responsibility for
maintaining. In particular here we exclude internal programming errors
(i.e., where the caller and callee are the responsibility of the same
person or team, such as inside a module), which are a separate category
normally dealt with using assertions (see Item 68).

Item 72: Prefer to use exceptions to report errors. When harmed, take
excpetion: Prefer using exceptions over error codes to report errors.
Use status codes (e.g., return codes, errno) for errors when exceptions
cannot be used (see Item 62), and for conditions that are not errors
[e.g., when a key is not found in a std::map --M]. Use other methods,
such as graceful or ungraceful termination, when recovery is impossible
or not required.

Cheers! --M
 
P

Phlip

mlimber said:
It sounded to me like you were saying that using assertions and
exceptions is pointless (like a two-legged stool) unless there are unit
tests to back them up and test them out thoroughly. I'm saying that
sometimes it is not practical to build such a unit test suite but that
even in those case, exceptions and assertions can still be of great
utility.

Always try to automate any test you can think of. Such tests reduce the time
you'll spend debugging, so they free up development time for more valuable
activities.
 
M

mlimber

Phlip said:
Always try to automate any test you can think of. Such tests reduce the time
you'll spend debugging, so they free up development time for more valuable
activities.

Of course, but sometimes that just isn't practical. That's my point.
(This is no longer a C++ discussion, by the way, but a software
engineering one.)

Cheers! --M
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

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

Latest Threads

Top