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
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:
Exit the block that received this
#on:do:, returning the given value.
You can also leave out the argument by sending
#return, in which case
it will be nil. If you want this handler to also handle exceptions in
whatever value you might provide, you should use
#retryUsing: with a
Acts sort of like a "goto" by restarting the first block. Obviously, this can lead to an infinite loop if you don’t fix the situation that caused the exception.
#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.
If you want to tell the exception to let an outer handler handle it,
#pass instead of
#signal. This is just like rethrowing
a caught exception in other languages.
This is the really interesting one. Instead of unwinding the stack,
this will effectively answer the argument from the
Code that sends
#signal to resumable exceptions can use this
value, or ignore it, and continue executing. You can also leave out
the argument, in which case the
#signal send will answer nil.
Exceptions that want to be resumable must register this capability by
true from the
#isResumable method, which is
checked on every
This is like
#pass, but if an outer handler uses
this handler block will be resumed (and
#outer will answer the
argument given to
#resume:) rather than the piece of code that
#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.