Posted on May 22, 2023
My love for Lisp languages is undying; among the Lisp dialects I prefer Scheme; once upon a time the Revised^6 Report on the Algorithmic Language Scheme was the proposed standard for new Scheme languages; it was not perfect; I liked a lot of its ideas about how to organise a language; I still like it.
I cannot help but trying to recycle r6rs’s ideas everywhere; I cannot design language features better than r6rs’s authors did. Among r6rs’s facilities that I like the most are exception handlers and exceptional–condition objects. So I implemented these features in mbfl taking heavy inspiration from r6rs.
Bash and Scheme are very different languages.
A core difference is that there is no way to rewind the call stack in Bash; when we raise an exception the execution flow will return from the raising command and we have to return to uplevel function calls by hard–coding the return statements. Life is hard!
Effective use of mbfl’s exception–handling is intertwined with the location mechanism: if an exception–handler exits the script, it can trigger the evaluation of all the current location handlers, in an attempt to perform the cleanest possible termination.
Exceptional–condition objects are described by classes; we can build a hierarchy of classes adding
attributes as we see fit; every exceptional–condition object’s class is a subclass of
mbfl_exceptional_condition_t
.
To instantiate an exceptional–condition object and then raise it, we do something like:
mbfl_default_object_declare(CND) mbfl_runtime_error_condition_make _(CND) $FUNCNAME 'synchronisation error' mbfl_exception_raise _(CND)
we can install any number of exception–handlers by pushing them on a stack, linked to the current hierarchy of locations; to install a new handler we do:
function myfunc () { mbfl_location_enter { mbfl_exception_handler 'myhandler' ... } mbfl_location_leave } function myhandler () { mbfl_mandatory_nameref_parameter(CND, 1, exceptional-condition object) ... }
An exception–handler can:
A default exception–handler is installed at mbfl startup to “gracefully” terminate the script in case of an uncaught exception.
When inside a location, to return–to–the–caller we should do something like:
mbfl_location_enter { ... if ! do_something_which_might_raise then mbfl_location_leave return_because_failure fi ... } mbfl_location_leave
I am still developing all of these facilities, but I pushed them on the master
branch because
there are enough features to try the thing and see how it goes.