To handle an exception when it occurs in a particular block of code,
#on:do: like this:
^[someText add: inputChar beforeIndex: i] on: ReadOnlyText do: [:sig | sig return: nil]
This code will put a handler for
ReadOnlyText signals on the
handler stack while the first block is executing. If such an exception
occurs, and it is not handled by any handlers closer to the point of
signalling on the stack (known as "inner handlers"), the exception object
will pass itself to the handler block given as the do: argument.
You will almost always want to use this object to handle the exception somehow. There are six basic handler actions, all sent as messages to the exception object:
#retry is a good way to implement reinvocation upon recovery,
because it does not increase the stack height. For example, this:
frobnicate: n [ ^[do some stuff with n] on: SomeError do: [:sig | sig return: (self frobnicate: n + 1)] ]
should be replaced with retry:
frobnicate: aNumber [ | n | n := aNumber. ^[do some stuff with n] on: SomeError do: [:sig | n := 1 + n. sig retry] ]
#retry, except that it effectively replaces the original block with the one given as an argument.
#signal. This is just like rethrowing a caught exception in other languages.
#signalsend. Code that sends
#signalto resumable exceptions can use this value, or ignore it, and continue executing. You can also leave out the argument, in which case the
#signalsend will answer nil. Exceptions that want to be resumable must register this capability by answering
#isResumablemethod, which is checked on every
#pass, but if an outer handler uses #resume:, this handler block will be resumed (and #outer will answer the argument given to #resume:) rather than the piece of code that sent #signal in the first place.
None of these methods return to the invoking handler block except for
#outer, and that only in certain cases described for it above.
Exceptions provide several more features; see the methods on the classes
Exception for the various things you can do
with them. Fortunately, the above methods can do what you want in almost
If you don't use one of these methods or another exception feature to exit
your handler, Smalltalk will assume that you meant to
whatever you answer from your handler block. We don't recommend relying
on this; you should use an explicit
sig return: instead.
A quick shortcut to handling multiple exception types is the
ExceptionSet, which allows you to have a single handler for the
exceptions of a union of classes:
^[do some stuff with n] on: SomeError, ReadOnlyError do: [:sig | ...]
In this code, any
ReadOnlyError signals will
be handled by the given handler block.