Handling of exceptions
You construct exception handlers by sending the message when:do: to a block. You can install multiple handlers simultaneously by using repeated forms of when:do: (that is, when:do:when:do:, when:do:when:do:when:do:, and so on) for up to five handlers. Because the handlers are tried in order, more general handlers should be placed later in the list. You can use nesting to allow more than five handlers if absolutely required.
The first argument to when:do: is an instance of class ExceptionalEvent. The second argument is a one-argument handler block that is passed the instance of Signal that describes the exception.
When an exception is signaled, the most recent when:do: matching the exception is evaluated first. When a when:do: message is found with either the exception or a more general exception (one of the exception's ancestors) as the when argument, its handlerBlock is run.
Within the handler block, the following methods can be sent to an instance of Signal:
Answers the first argument that was passed to the signal message, or nil if none.
Answers a collection containing any arguments that were passed to the signal message.
Immediately returns an object instance as the value of the when:do: exception.
Returns key and value as the result of the signal message.
Indicates that the current handler is finished handling, or is not going to handle, the exception and that a search for another handler should begin. Notice that this is not the same semantics as sending signal to an instance of ExceptionalEvent.
Same as signal, but modifies the arguments which are passed on.
Same as signal, but modifies the arguments which are passed on.
Same as signal, but modifies the arguments which are passed on.
Runs the block that the when:do: message was sent to. All handlers are reinstated.
Runs the default handler for the exception.
Answers a description of the exception. Returns the string `an exception has occurred' if no description was set in the ExceptionalEvent.
Answers the exception that was signaled. Access to the exception is not normally required by handlers. However, this method is provided for special purpose applications.
Assuming that ThatException is a global variable, an application could have the following code:
"Initialization code."
(ThatException := ExAll newChild)
description: 'That exception occurred.'.
"Answer true if thatTest completes without error,
otherwise signal ThatException."
self thatTest failed
ifTrue: [ThatException signal].
The application has determined that an exceptional condition has occurred and signals an exception.
"The application can then do something like the following.
Answer true if thatMethod completes without exception,
and false otherwise."
^ self thatMethod ]
when: ThatException
do: [:signal |
"Handle the exception in some way: increment a counter,
print a message, fix a problem, ... and then exit the handler."
signal exitWith: false].
From do: [:signal to the end is the handler block.
Note that "dropping off the end" of a handler block is equivalent to sending
resumeWith: (Association
key: #resume
value: valueOfTheBlock
where valueOfTheBlock is the value of the handler block.
Neither the handler block nor the block that receives when:do: can contain a return (^) expression. Although this is not a significant limitation, it should be kept in mind when automatic code generation techniques are used, because arbitrary code fragments cannot be wrapped with exception handlers without first checking for return expressions.
It is possible to signal another exception within the body of the handler.
The handler block should not contain a return (^) expression. Returning from an exception handler can cause unpredictable results.
Last modified date: 01/29/2015