5.3.9  Exceptions

Most modern languages have some sort of mechanism for aborting a subcomputation which has gone seriously wrong and picking up again at an appropriate recovery point.

For example C has setjmp() and longjmp() and Python has try: ... except SomeError: ... .

Mythryl has a facility which is quite similar in function and application, albeit with some interesting twists.

The Mythryl exception handling machinery consists of three fundamental parts:

A typical use might look something like:

    fun foo ()
        {   exception FOUND_IT( Int );
            exception NOT_FOUND;

            fun do_deep_recursive_search ()
                {    ...
                     raise exception NOT_FOUND;       # Oh well.
                     raise exception FOUND_IT( n/32 + 6 );

            do_deep_recursive_search ()
                NOT_FOUND   => printf "Could not find answer!\n";
                FOUND_IT(i) => printf "The answer is %d.\n" i;

Mythryl exceptions may carry arbitrary information. They are defined via declarations like

    exception DISK_ERROR;
    exception OUT_OF_RAM;
    exception TERMINATED_BY_SIGNAL_FROM_PROCESS( Int   );       # Int value is pid of external process.
    exception VIOLATION_OF_ACCESS_CONTROL_RULE( String );       # String value is text of rule. 

These declarations behave a lot like a vanilla sumtype declaration

    Exception = DISK_ERROR
              | OUT_OF_RAM;
              | VIOLATION_OF_ACCESS_CONTROL_RULE( String );

The exception declarations differ primarily in that constructors declared with exception may be used as arguments to raise exception and except.

The Mythryl raise exception construct is used to change the flow of control by activating the exception handling machinery. It is logically a lot like longjmp() in C.

One difference is that the C longjmp() function is not very efficient; the usual implementation has to sequentially search down the stack until it finds a registered setjmp() handler. The Mythryl raise exception construct, by contrast, is implemented very efficiently. The mechanism used is essentially identical to that used to return from a Mythryl function call, and consequently executes just as quickly. Mythryl raise exception and except are sometimes used as a simple non-local goto, quite independently of any consideration of exceptional conditions.

The Mythryl except construct is in essence a specialized case statement. Like function definitions, it has separate syntax for the single-alternative and multi-alternative cases:

    exception SOME_EXCEPTION; 
    exception EXCEPTION_ONE(String); 
    exception EXCEPTION_TWO(Float); 

    # Single-exception syntax:
    some_expression ()
        SOME_EXCEPTION = printf "Encountered SOME_EXCEPTION\n";

    # Multi-exception syntax:
    some_expression ()
        EXCEPTION_ONE(string) => printf "Encountered EXCEPTION_ONE(%s)\n" string;
        EXCEPTION_TWO(float)  => printf "Encountered EXCEPTION_TWO(%f)\n" float ;

As always, the single-alternative form uses = and has no end while the multi-alternative form uses => and has an end trailing the final alternative.

The Mythryl standard library safely package provides canned functionality for protecting a computation from exceptions. It is often used to, for example, read from a file while guaranteeing that the file will be closed properly should any exception be raised, by catching the exception, closing the file, and then re-raising the exception.

Comments and suggestions to: