Effective use of MBFL’s exception–handling is intertwined with the location mechanism, Running location handlers.
Exceptional conditions are described by instances of appropriate exceptional–condition classes,
Exceptional–condition objects. It is mandatory to use only
exceptional–condition objects whose class is a subclass of mbfl_exceptional_condition
; no
other Bash value is allowed.
Whenever an exceptional–condition object is “raised” an exception–handling function is called to
react to it; such function is called exception–handler. To raise an exceptional–condition
we apply the function mbfl_exception_raise()
to the object’s data variable:
if ! try_an_action 1 2 3 then mbfl_default_object_declare(CND) mbfl_runtime_error_condition_make _(CND) $FUNCNAME 'failed action' mbfl_exception_raise _(CND) fi
MBFL allows us to push exception–handlers onto a global stack, in such a way that handlers are made “local” by removing them upon leaving the current location. Here is how to write a function:
function do_some_thing () { mbfl_location_enter { mbfl_exception_handler 'handle_some_exceptions' # do some thing } mbfl_location_leave }
while “do some thing” code is running: if an exception is raised, the exception–handler
handle_some_exceptions()
is applied to the exceptional–condition object; upon leaving the
location handle_some_exceptions()
is popped from the stack.
Compared to other languages: MBFL’s exception–handling is peculiar because, under Bash, there is
no automatic call stack unwinding; when needed we must return
from all the functions until we
reach a “beginning of task” function. We must partition the code into an appropriate number of
nested functions. We can organise code as follows:
function main () { declare -i RETURN_STATUS perform_an_operation RETURN_STATUS=$? if (( 0 != RETURN_STATUS )) then exit_failure fi exit_success } function perform_an_operation () { mbfl_location_enter { mbfl_exception_handler 'an_exception_handler' if ! operation_step_one then mbfl_location_leave return_because_reason fi if ! operation_step_two then mbfl_location_leave return_because_another_reason fi } mbfl_location_leave return_success } function operation_step_one () { mbfl_location_enter { mbfl_exception_handler 'another_exception_handler' if ! do_some_thing then if ! raise_an_exception then mbfl_location_leave return_because_bad_reason fi fi if ! do_some_other_thing then if ! raise_another_exception then mbfl_location_leave return_because_another_bad_reason fi fi } mbfl_location_leave return_success }
We can push any number of handlers in each location:
function perform_an_operation () { mbfl_location_enter { mbfl_exception_handler 'an_exception_handler' mbfl_exception_handler 'another_exception_handler' # do some thing } mbfl_location_leave return_success }
whenever an exceptional–condition is raised: the topmost handler is applied to the object; it might:
in the last case: the next handler from the stack is applied to the object and so on until some handler handles the exception. A default handler is pushed to the stack upon MBFL loading–time: if it is called, it might terminate the script with a “uncaught exception” exit status.
This document describes version 3.0.0-devel.9 of Marcos Bash Functions Library.