Exceptions/Catch an exception thrown in a nested call: Difference between revisions
Content added Content deleted
(→{{header|Smalltalk}}: Incomplete) |
(Update Smalltalk example (remove box about being incomplete)) |
||
Line 2,675: | Line 2,675: | ||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
{{works with|GNU Smalltalk}} |
|||
{{incomplete|Smalltalk|"Show/describe what happens when the program is run."}} |
|||
<lang smalltalk> |
|||
{{works with|Smalltalk/X}}functional code, not class based, |
|||
Exception subclass: #U0. |
|||
using blocks as functions, and anonymous exceptions (signals): |
|||
Exception subclass: #U1. |
|||
<lang Smalltalk>| u0 u1 foo bar baz| |
|||
Object subclass: Foo [ |
|||
u0 := Signal new. |
|||
u1 := Signal new. |
|||
bazCount := 0. |
|||
2 timesRepeat:[ |
|||
[ bar value ] |
|||
on: u0 |
|||
do:[ 'u0 cought' printCR ] |
|||
] |
|||
]. |
|||
foo |
|||
bar := [ |
|||
[2 timesRepeat: |
|||
] |
[ "==>" [self bar] "<==" |
||
on: U0 |
|||
do: |
|||
[:sig | |
|||
'Call to bar was aborted by exception U0' printNl. |
|||
sig return]]] |
|||
bar |
|||
baz := [ |
|||
[self baz] |
|||
baz |
|||
[bazCount := bazCount + 1. |
|||
alreadyCalled isNil ifTrue:[ |
|||
bazCount = 1 ifTrue: [U0 new signal]. |
|||
bazCount = 2 ifTrue: [U1 new signal]. |
|||
"Thirds time's a charm..."] |
|||
] |
|||
] |
|||
</lang> |
|||
] |
|||
] value. |
|||
Running the code: |
|||
foo value</lang> |
|||
<lang Smalltalk> |
|||
"traditional" implementation, using class based exceptions, |
|||
st> Foo new foo |
|||
and method invocations: |
|||
'Call to bar was aborted by exception U0' |
|||
<lang Smalltalk>Exception |
|||
Object: Foo new "<-0x4c9a7960>" error: An exception has occurred |
|||
subclass: #U0 |
|||
U1(Exception)>>signal (ExcHandling.st:254) |
|||
instanceVariableNames:'' |
|||
Foo>>baz (catch_exception.st:32) |
|||
classVariableNames:'' |
|||
Foo>>bar (catch_exception.st:27) |
|||
poolDictionaries:'' |
|||
optimized [] in Foo>>foo (catch_exception.st:19) |
|||
category:'example'. |
|||
BlockClosure>>on:do: (BlkClosure.st:193) |
|||
Foo>>foo (catch_exception.st:20) |
|||
UndefinedObject>>executeStatements (a String:1) |
|||
nil |
|||
</lang> |
|||
Explanation:<br/> |
|||
Exception |
|||
Inside the foo method, inside the 2 timesRepeat: block, there is a small |
|||
subclass: #U1 |
|||
block <code>[self bar]</code> which simply calls bar. This block is sent |
|||
instanceVariableNames:'' |
|||
the <code>#on:do:</code> message, which will evaluate the block and catch |
|||
classVariableNames:'' |
|||
any mentioned exception. First time this block is evaluated, it results in |
|||
poolDictionaries:'' |
|||
a U0 exception, which we catch and handle by printing a message and |
|||
category:'example'. |
|||
returning <code>nil</code> in place of whatever the block would have |
|||
returned. The second time the block is evaluated, it results in a U1 |
|||
exception, which we do ''not'' catch, so it passes to the default handler |
|||
which prints a trace and exits. The second line of the trace |
|||
<code>U1(Exception)>>signal</code> shows that this was a U1 exception. |
|||
Exception handling in Smalltalk is exceptional, and the exception handler |
|||
Object |
|||
(the following do: block) can do quite some cool stuff, like retrying the |
|||
subclass: #CatchMeIfYouCan |
|||
block, retrying with a different block, and even resuming evaluation at the |
|||
instanceVariableNames:'bazAlreadyCalled' |
|||
point where the exception was raised (baz in this example) having <code>U0 |
|||
classVariableNames:'' |
|||
new signal</code> return some value. |
|||
poolDictionaries:'' |
|||
category:'example'. |
|||
" CatchMeIfYouCan methods " |
|||
foo |
|||
2 timesRepeat:[ |
|||
[ self bar ] |
|||
on: U0 |
|||
do:[ 'U0 cought' printCR ] |
|||
] |
|||
bar |
|||
self baz |
|||
baz |
|||
bazAlreadyCalled isNil ifTrue:[ |
|||
bazAlreadyCalled := true. |
|||
U0 raise |
|||
] ifFalse:[ |
|||
U1 raise |
|||
] |
|||
CatchMeIfYouCan new foo</lang> |
|||
=={{header|Swift}}== |
=={{header|Swift}}== |