12.3: Handling Non-Local Returns
- Page ID
- 43731
The message ifCurtailed:
is typically used for “cleaning” actions. It is similar to ensure:
, but instead of ensuring that its argument block is evaluated even if the receiver terminates abnormally, ifCurtailed:
does so only if the receiver fails or returns.
In the following example, the receiver of ifCurtailed:
performs an early return, so the following statement is never reached. In Smalltalk, this is referred to as a non-local return. Nevertheless the argument block will be executed.
[^ 10] ifCurtailed: [Transcript show: 'We see this']. Transcript show: 'But not this'.
In the following example, we can see clearly that the argument to ifCurtailed:
is evaluated only when the receiver terminates abnormally.
[Error signal] ifCurtailed: [Transcript show: 'Abandoned'; cr]. Transcript show: 'Proceeded'; cr.
\(\bigstar\) Open a transcript and evaluate the code above in a workspace. When the pre-debugger windows open, first try selecting Proceed
and then Abandon
. Note that the argument to ifCurtailed:
is evaluated only when the receiver terminates abnormally. What happens when you select Debug
?
Here are some examples of ifCurtailed:
usage: the text of the Transcript show:
describes the situation:
[^ 10] ifCurtailed: [Transcript show: 'This is displayed'; cr] [10] ifCurtailed: [Transcript show: 'This is not displayed'; cr] [1 / 0] ifCurtailed: [Transcript show: 'This is displayed after selecting Abandon in the debugger'; cr]
Although in Pharo ifCurtailed:
and ensure:
are implemented using a a marker primitive (described at the end of the chapter), in principle ifCurtailed:
could be implemented using ensure:
as follows:
ifCurtailed: curtailBlock | result curtailed | curtailed := true. [ result := self value. curtailed := false ] ensure: [ curtailed ifTrue: [ curtailBlock value ] ]. ^ result
In a similar fashion, ensure:
could be implemented using ifCurtailed:
as follows:
ensure: ensureBlock | result | result := self ifCurtailed: ensureBlock. "If we reach this point, then the receiver has not been curtailed, so ensureBlock still needs to be evaluated" ensureBlock value. ^ result
Both ensure:
and ifCurtailed:
are very useful for making sure that important “cleanup” code is executed, but are not by themselves sufficient for handling all exceptional situations. Now let’s look at a more general mechanism for handling exceptions.