assert to exception : what is the scenario

L

linq936

Hi,
I have many assert() call in my code, now I am considering to replace
them with exception. The reason I want to do this change is that with
the program going bigger and bigger, it is hard to test all the corner
cases, and thus assert() does not work as good as before. The problem
is if there are something really bad which was not captured by
assert(), then in runtime, most likely the program will crash. This is
the worst user experience.

Exception at least is better in that it has "graceful" exit.

I did not use exception before as I was told gcc3.2.2 did not support
exception very well, now my company is using gcc 3.2.3 which I am told
is better to handle exception. (Is this true?)

My current plan is to do some sort of editor string replacement so
that assert() is to be exception.

One thing is, I use lofs of assert(), some of them are in pretty deep
function call chain stack, then that means I need to add "throw
exception" declaration to almost all the functions.

While I will only have one catch statement on the very top, so in
order for the top function to receive the exception, I need to have
"throw exception" all the way from the deepest function in the stack.

How do you think my plan, how about gcc3.2.3 exception support?

Any suggestion is highly appreciated.
 
P

Peter Koch Larsen

Hi,
I have many assert() call in my code, now I am considering to replace
them with exception. The reason I want to do this change is that with
the program going bigger and bigger, it is hard to test all the corner
cases, and thus assert() does not work as good as before. The problem
is if there are something really bad which was not captured by
assert(), then in runtime, most likely the program will crash. This is
the worst user experience.

Exception at least is better in that it has "graceful" exit.

Assert is for debug, thus the user should not see that. But let us assume
that you do send your debug-code to beta-testers. In that case, the assert
is much better. It gives you a core dump that helps you find out what the
problem is.
I did not use exception before as I was told gcc3.2.2 did not support
exception very well, now my company is using gcc 3.2.3 which I am told
is better to handle exception. (Is this true?)
Unfortunately, I cannot help you here.
My current plan is to do some sort of editor string replacement so
that assert() is to be exception.
If you decide to hang on to your scheme, you should probably replace the
assert-macro with another macro. That macro could then test the condition
and do the job. Something like
#define assert_throw(_cond) do { if (!_cond) throw
my_assert_signal(#_cond); } while (false)
One thing is, I use lofs of assert(), some of them are in pretty deep
function call chain stack, then that means I need to add "throw
exception" declaration to almost all the functions.
No. Only if those functions have a throw-specification already.
While I will only have one catch statement on the very top, so in
order for the top function to receive the exception, I need to have
"throw exception" all the way from the deepest function in the stack.

How do you think my plan, how about gcc3.2.3 exception support?

I believe assert is for debug-builds only - not something you would send to
a real user. Perhaps some of your asserts check your environment instead of
your logic?
Any suggestion is highly appreciated.

/Peter
 
D

davidrubin

Hi,
I have many assert() call in my code, now I am considering to replace
them with exception. The reason I want to do this change is that with
the program going bigger and bigger, it is hard to test all the corner
cases, and thus assert() does not work as good as before. The problem
is if there are something really bad which was not captured by
assert(), then in runtime, most likely the program will crash. This is
the worst user experience.

Exception at least is better in that it has "graceful" exit.

You should only use 'assert' in cases where the program *should* abort
if the assertion fails. In particular, use assert to enforce program
invariants (e.g,. a value that you stored into a container is in the
container when you 'find' it).

Use exceptions for *exceptional* errors for which there may or may not
be a recovery action (e.g., could not allocate memory from a pooled
allocator).

Use return codes for all other errors (e.g., could not connect to
server, result of translation from string to int failed, etc).

As for testing corner cases, an effective method is to break your
program into a hierarchy of (small) components with an explicitly
stated contract for each method, and test each component completely in
isolation from the bottom up. It helps a great deal to *state* the
contract for each method (what values are returned under various
circumstances, what is undefined behavior, what are the effects of
error conditions on arguments, etc) both for the purpose of writing the
implementation and for testing the method. If you can state the domain
and range of a function, it is fairly straightforward to test it.

/david
 
L

linq936

Peter said:
Assert is for debug, thus the user should not see that. But let us assume
that you do send your debug-code to beta-testers. In that case, the assert
is much better. It gives you a core dump that helps you find out what the
problem is.

Unfortunately, I cannot help you here.
If you decide to hang on to your scheme, you should probably replace the
assert-macro with another macro. That macro could then test the condition
and do the job. Something like
#define assert_throw(_cond) do { if (!_cond) throw
my_assert_signal(#_cond); } while (false)
No. Only if those functions have a throw-specification already.


I believe assert is for debug-builds only - not something you would send to
a real user. Perhaps some of your asserts check your environment instead of
your logic?


/Peter

Thanks for the reply.

Like you said assert() is for debug, for my case the assert() call will
be removed in optimized compile, it only stays in the debug version.

One thing I want to make sure, let's say the function call is like
this:
func1()
--> func2()
--> func3()
In func3() I throw an exception, and func3() declares "throw
exception". Then in order for func1() to receive the exception, func2()
must declares "throw expetion". Is this right?

More details like this,

int func1(){
...
try {
func2();
}
catch excpetion {
...
}
}

int func2() throw exception {
^^^^^^^^^^^^^^^^ -- I must have this declaration,
right?
func3();
}

int func3() throw exception {
...
throw exception;
}
 
H

Howard

Like you said assert() is for debug, for my case the assert() call will
be removed in optimized compile, it only stays in the debug version.

One thing I want to make sure, let's say the function call is like
this:
func1()
--> func2()
--> func3()
In func3() I throw an exception, and func3() declares "throw
exception". Then in order for func1() to receive the exception, func2()
must declares "throw expetion". Is this right?

More details like this,

int func1(){
...
try {
func2();
}
catch excpetion {
...
}
}

int func2() throw exception {
^^^^^^^^^^^^^^^^ -- I must have this declaration,
right?
func3();
}

int func3() throw exception {
...
throw exception;
}

Now you're talking about exception specifications. There is no requirement
that you provide exception specifications. Any function can throw an
exception, and any calling function can catch exceptions (either using the
catch-all "..." or the specific exception type). You do not have to declare
(nor have I ever used) exception specifications (unless of course that is
something your employer requires). Exception specifications do not actually
allow or prevent exceptions from being passed (or caught), but are rather
intended as a tool for programmers to use to know what exceptions *might* be
expected to be thrown out of a given function. But in practice, that may be
incredibly difficult to know for sure, and in the opinion of many (myself
included) they're just a waste of time.

-Howard
 
M

Marcin Kalicinski

While I will only have one catch statement on the very top, so in
order for the top function to receive the exception, I need to have
"throw exception" all the way from the deepest function in the stack.

Reading your description I do not think you will really benefit from
exceptions. The strength of exceptions is that they may be caught and
handled everywhere. If you only provide a top level catch clause (presumably
with some user interface telling that program is shutting down), you might
as well replace all asserts with a call to the function that does exactly
the same.

I do not see why you think that exceptions shut program more gracefully than
asserts. I believe it makes no difference whatsoever - the program just
crashes in both cases.

Moreover, it is often much easier to debug an assert-crashing program than
exception-crashing. The reason is the stack frame is still there in case of
assert, while in top-level exception handler it is already completely
unwound and useless. In other words you don't know where the exception is
coming from, unless you include that information in the exception itself.

cheers,
M.
 
L

linq936

Marcin said:
stack.

Reading your description I do not think you will really benefit from
exceptions. The strength of exceptions is that they may be caught and
handled everywhere. If you only provide a top level catch clause (presumably
with some user interface telling that program is shutting down), you might
as well replace all asserts with a call to the function that does exactly
the same.

I do not see why you think that exceptions shut program more gracefully than
asserts. I believe it makes no difference whatsoever - the program just
crashes in both cases.

Moreover, it is often much easier to debug an assert-crashing program than
exception-crashing. The reason is the stack frame is still there in case of
assert, while in top-level exception handler it is already completely
unwound and useless. In other words you don't know where the exception is
coming from, unless you include that information in the exception itself.

cheers,
M.
While I do not quite agree with you. assert() is a macro, when you
build the code without DEBUG in the compiler option, it disappears from
the code. And if an error slips by, then it means crash.

Exception is better here because you can tell user some fatal error
happens, but user has the choise either close the application or call
some other utility. This does not cause the whole software crash.

I prefer exception over calling a function in that you still need come
out that function at some point, so you are still in trouble.

Thanks.
 
A

Andre Caldas

Moreover, it is often much easier to debug an assert-crashing program
than


case of


exception is


While I do not quite agree with you. assert() is a macro, when you
build the code without DEBUG in the compiler option, it disappears from
the code. And if an error slips by, then it means crash.

The fact that it is a macro and it disapears from your code is a
feature. Assert is for testing correctness of your code. Assert
disapears when you are not debugging because this allows you to call
some heavy checking function inside it. For example:

* You could have a linked list (or some structure more complex). You may
want to test in many places if "n->next->prev == n" or not. You may want
to do this after each removal, or addition of elements. And you may want
to do for every element on the list for each addition or removal.

Also, you may enforce some policy: "Whenever you call a certain member
function, the object must necessarly be in a certain state. If it is
not, then it is a bug."

Exception is better here because you can tell user some fatal error
happens, but user has the choise either close the application or call
some other utility. This does not cause the whole software crash.

Assertions are there to prove that your code is right. What you want to
do needs no execption. Just a function for "cleaning up the mess".

I prefer exception over calling a function in that you still need come
out that function at some point, so you are still in trouble.

Assertion is not what you want because it is for development. But don't
assume that exception *is* what you want. Maybe you should do something
like:
assert( fact );
if ( ! fact ) clean_up_the_mess( __FILE__, __LINE__ );

But some "execptions" are not necessarly bugs (they could be a bad
input). And some bugs are very unlikely to happen if you passed the
development fase without them beeing "catched" by your "assertions". So,
some times you only need an "assert", some times you only need your
"clean_up_the_mess", and some times you need both.

By the way, what Marcin was saying was that it is much better to have a
clean_up_the_mess function then simply "if ( !fact ) throw MyException;"
because the exception messes up with the call stack.

Another thing. If you use assert for something that is not a real bug,
for example, a wrong input that would overflow some buffer, then you are
in trouble because the non-debug version will contain a buffer overflow
bug. Assert is for debugging only. Your program behaviour, supposing it
is free of bugs, should not change if they are ommited or not.

Andre Caldas.
 
J

John Dibling

Check out "Debugging Production Software" in the June, 2005 edition of
Dr. Dobb's.

</dib>
 
L

linq936

Andre said:
The fact that it is a macro and it disapears from your code is a
feature. Assert is for testing correctness of your code. Assert
disapears when you are not debugging because this allows you to call
some heavy checking function inside it. For example:

* You could have a linked list (or some structure more complex). You may
want to test in many places if "n->next->prev == n" or not. You may want
to do this after each removal, or addition of elements. And you may want
to do for every element on the list for each addition or removal.

Also, you may enforce some policy: "Whenever you call a certain member
function, the object must necessarly be in a certain state. If it is
not, then it is a bug."



Assertions are there to prove that your code is right. What you want to
do needs no execption. Just a function for "cleaning up the mess".



Assertion is not what you want because it is for development. But don't
assume that exception *is* what you want. Maybe you should do something
like:
assert( fact );
if ( ! fact ) clean_up_the_mess( __FILE__, __LINE__ );
Let's say the function statck is like this,
main()
---> fun1()
---> fun2()
and in fun2() you have this clean_up_the_mess() called. The problem is
for the bug that assert() did not catch in debug version, that usually
is a critical one, that means after you clean up the messed
environment, the only option for you is to exit, not continue. But the
problem is you need to exit all the way from fun2(), to fun1(), and to
main() finally.

You need to have the code in each function to check the return the
value of the sub-function, fun1() checks fun2(), main() checks fun1(),
etc. Well this should be a good practice, in reality world, we do not.

That is the thing I love exception, it unwinds the function call stack
all the way up, until some point you believe it is necessary to do
clean up.

Maybe I do not get your idea in full, enjoying this thread.
 
H

Hang Dog

Hi,
I have many assert() call in my code, now I am considering to replace
them with exception. The reason I want to do this change is that with
the program going bigger and bigger, it is hard to test all the corner
cases, and thus assert() does not work as good as before.

<brag-mod>
The last time I checked our application has some 3,500,000 LOC
</brag-mod>

We use assertions everywhere and never throw. Our debug code runs 20-30
times slower than release primarily due to the assertion checks. The
level of checks that are perform could not be realistically done in
release code.

The problem
is if there are something really bad which was not captured by
assert(), then in runtime, most likely the program will crash. This is
the worst user experience.

Exception at least is better in that it has "graceful" exit.


Assertions test for programmer errors, exceptions test for user errors.
In the first case the program should crash, in the second case it shouldn't.
 

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
474,203
Messages
2,571,059
Members
47,668
Latest member
SamiraShac

Latest Threads

Top