Navigation: Programming Cookbook > Exception Handling >
How it works
The exception handling system in Dolphin is written entirely in Smalltalk (though it does rely on the VM's special support for unwind blocks), and is a good example of the systems reflective capabilities - because even the execution state of a program is accessible to that program (as objects of course), it is possible for a program to modify its execution state, and this is precisely what the exception handling system does.
It is not necessary to understand precisely how exceptions work in Dolphin, but an overview may be helpful in when using them, and will gives some idea of the overhead involved. To learn more about the implementation of exceptions in Dolphin, browse through the source code in Exception (and its immediate subclasses), and ExceptionHandlerAbstract (and its subclasses).
Each Dolphin process maintains a 'stack' of exception contexts, with a new one being instantiated and pushed on the stack for each #on:do:. The exception context includes all relevant details from the #on:do: message, and from the execution state at the time of the message. As #on:do:'s exit, the corresponding exception context is popped from the stack.
Note that establishing an #on:do: handler carries the overhead of instantiating an exception context. A similar overhead is present in the implementation of the native "structured exceptions" on Win32 platforms, for example in C++, except that the compiler hides the implementation details. This overhead is incurred regardless of whether any exceptions are actually raised.
An exception is raised by instantiating a suitable instance of an exception class with pertinent details relating to the exceptional condition (e.g. in the case of a BoundsError, the receiver and the index which is out of bounds), and sending it the #signal message, though frequently this is wrapped inside a shortcut instance creation method provided by the exception class.
When an exception is raised in a Process, execution is effectively suspended, though only in the same way that any method execution is suspended when it sends a message and another method is invoked, and the exception system begins a search through the stack of exception contexts. At each level, the exception context is queried to see if it is suitable for handling the raised exception. Typically this matching operation is simply an #isKindOf: test to see if the class of the raised exception is the same kind as the class of exception specified by the handler, but more sophisticated matching is possible (for example against a set of Exception classes). The stack will tend to be only a few contexts deep, so this is a very fast search, but the overhead relative to the alternative of explicitly checking for an error is high, although it is only incurred if the exceptional case.
If an exception context is located which wants to handle the exception, then the corresponding handler block is evaluated with the exception instance as the argument. The handler block can take any of the handler actions, with these mostly being implemented by evaluating blocks containing ^-returns that were captured at appropriate points to allow for resumption of execution at the desired point.