I get asked about Smalltalk exception handling from time to time, and - specifically - I get asked how it differs from what's done in Java. The primary difference is in how the context stack is handled. In Java, when you get to the handler code, the stack has been unwound and is just gone. Not so in Smalltalk - as a matter of fact, the stack is an argument held in the exception. Here's a simple example - I'll use the NetResources library to try and retrieve a non-existant url, and toss a breakpoint into the handler code so you can see what's going on. Here's the relevant code:
response := [client executeRequestDo:
[:connection | client getNotifyingResponse: connection]]
on: (self class httpExceptions, Error)
do: [:ex | self behaviourForException: ex. nil].
We've wrapped the actual HTTP request in a handler that sends all exceptions to a method called #behaviorForException:. That's done so that we can respond appropriately based on the kind of exception that crops up. Here's that method:
behaviourForException: ex
ex class = Security.SSLBadCertificate
ifTrue: [Security.X509.X509Registry default addCertificate: ex parameter parameter].
(self class possibleTimeoutExceptions includes: ex class)
ifTrue: [self updateCacheResponseCodeOnly.
^self class triggerTimeoutEvent: url].
(ex isResumable and: [self class exceptionsWeShouldResume includes: ex class] )
ifTrue: [ex resume]
ifFalse: [self reportTheErrorType: ex]
See that part at the bottom that checks for resumable (and worth resuming) exceptions? If we get there, what will happen is simple - the system will return to the point where the exception got thrown, and simply proceed as if it hadn't happened. You might ask yourself, why would we want to do that? As it happens, there's code in the calling method to handle things like HTTP redirects and Authorization requests - so those exceptions are simply resumed. So anyway, a brief demonstration - here's a screen shot of an attempt to fetch a non-existant URL:
Now, here's an inspector on the exception:
And drilling down, the context itself:
All of which shows how it can be useful to have access to the full stack in a handler. resuming isn't the only thing you can do, either - you can have the exception return to the (original) caller with some default value, you can resend the exception (or another) - it's pretty wide open.