12.11: Exceptions and ensure, ifCurtailed Interaction
- Page ID
- 45969
Now that we saw how exceptions work, we present the interplay between exceptions and the ensure:
and ifCurtailed:
semantics. Exception handlers are executed then ensure:
or ifCurtailed:
blocks are executed. ensure:
argument is always executed while ifCurtailed:
argument is only executed when its receiver execution led to an unwound stack.
The following example shows such behavior. It prints: should show first error
followed by then should show curtailed
and returns 4.
[[ 1/0 ] ifCurtailed: [ Transcript show: 'then should show curtailed'; cr. 6 ]] on: Error do: [ :e | Transcript show: 'should show first error'; cr. e return: 4 ].
First the [1/0]
raises a division by zero error. This error is handled by the exception handler. It prints the first message. Then it returns the value 4 and since the receiver raised an error, the argument of the ifCurtailed:
message is evaluated: it prints the second message. Note that ifCurtailed:
does not change the return value expressed by the error handler or the ifCurtailed:
argument.
The following expression shows that when the stack is not unwound the expression value is simply returned and none of the handlers are executed. 1 is returned.
[[ 1 ] ifCurtailed: [ Transcript show: 'curtailed'; cr. 6 "does not display it" ]] on: Error do: [ :e | Transcript show: 'error'; cr. "does not display it" e return: 4 ].
ifCurtailed:
is a watchdog that reacts to abnormal stack behavior. For example, if we add a return statement in the receiver of the previous expression, the argument of the ifCurtailed:
message is raised. Indeed the return statement is invalid since it is not defined in a method.
[[ ^ 1 ] ifCurtailed: [ Transcript show: 'only shows curtailed'; cr. ]] on: Error do: [ :e | Transcript show: 'error 2'; cr. "does not display it" e return: 4 ].
The following example shows that ensure:
is executed systematically, even when no error is raised. Here the message should show ensure
is displayed and 1 is returned as a value.
[[ 1 ] ensure: [ Transcript show: 'should show ensure'; cr. 6 ]] on: Error do: [ :e | Transcript show: 'error'; cr. "does not display it" e return: 4 ].
The following expression shows that when an error occurs the handler associated with the error is executed before the ensure:
argument. Here the expression prints should show error first
, then then should show ensure
and it returns 4.
[[ 1/0 ] ensure: [ Transcript show: 'then should show ensure'; cr. 6 ]] on: Error do: [ :e | Transcript show: 'should show error first'; cr. e return: 4 ].
Finally the last expression shows that errors are executed one by one from the closest to the farthest from the error, then the ensure:
argument. Here error1
, then error2
, and then then should show ensure
are displayed.
[[[ 1/0 ] ensure: [ Transcript show: 'then should show ensure'; cr. 6 ]] on: Error do: [ :e| Transcript show: 'error 1'; cr. e pass ]] on: Error do: [ :e | Transcript show: 'error 2'; cr. e return: 4 ].