Ben Bacarisse said:
I don't see it yet. How does control get here if the called function
(or one it calls) throws an exception?
Basically, each function in the call chain would have the same
test-and-return line at selected points - usually after each call to a
function which could result in an exception - though there are variations.
It is probably clearest if I try to explain what I mean by variations by
making up an example showing different scenarios. Bear in mind that the
overall idea is something I am experimenting with. It is not yet a fully
worked solution that I would recommend to others. It is just something that
seems to be working well for me.
Imagine there are four functions which form a call chain as in
A -> B -> C -> D
So function A calls B, B calls C, and C calls D. Each deals with exceptions
differently but they have to work together. Let's say that D may throw an
exception. Function C does not handle any exceptions at all. That is
probably the most common case. B handles some specific exceptions. Function
A is the final "catcher" for the application and handles all catchable
exceptions one way or another. It could take remedial action in some cases
but in this example it will just report them to a person.
The code in the four functions would be along the following lines.
Function A catches all catchable exceptions and reports them. So after a
call to B it only needs to test whether variable "exception" is non-zero and
if it is to act accordingly.
void A(void) {
.... other code ....
B();
if (exception) {
printf("\n%s exception in %s at line %u\n",
exception_typename_get(exception),
exception_filename_get(),
exception_linenum_get());
}
.... other code ....
}
Function B handles some specific exception types so it might use a switch
statement in order to select which path to take. This is similar to the
traditional use of multiple catch clauses.
void B(void) {
.... other code ....
C();
switch (exception) {
case 0:
break; /* Nothing went wrong */
case EXCEPTION_RANGE:
/* Handle range exception */
exception_cancel();
break;
default:
return; /* Not handled here. Go to caller */
}
.... other code ....
}
Function C doesn't catch any exceptions at all so if one occurs it
immediately returns to its caller.
void C(void) {
.... other code ....
D();
if (exception) return;
.... other code ....
}
Finally, function D doesn't handle exceptions but may throw one or two.
void D(void) {
.... other code ....
if (condition1) {
exception_throw(EXCEPTION_RANGE, __FILE__, __LINE__,
"D", 0);
return;
}
.... other code ....
if (condition2) {
exception_throw(EXCEPTION_USER, __FILE__, __LINE__,
"D", 0);
return;
}
.... other code ....
}
Note that 'throwing' the exception just sets the exception variables. D must
still return to its caller.
In the above scenario, if D throws EXCEPTION_RANGE the effect will be as if
function C was skipped and the exception will be caught by B. If D throws
EXCEPTION_USER the effect will be as if both C and B were skipped and the
exception will be caught by function A.
Note that although B catches the EXCEPTION_RANGE type it does not have to
deal with all such exceptions. After other tests on what specifically went
wrong it could decide either to deal with the issue - in which case it will
call exception_cancel() - or that it doesn't want to deal with the issue -
in which case it will return to its caller with the exception object
unchanged.
The above illustrative code is just as typed in and is untested. I may have
missed something but I hope it gives the idea.
Comments welcome.
James