Wednesday, May 18, 2005

Resumable Exceptions

Time for another "this is why Smalltalk is cool" post, but this one also holds true for Ruby And Lisp as well. So, it's a "why Smalltalk, Ruby, and Lisp kicks mucho booty" so to speak. OK, enough of the back patting and let's get down to business. Today's topic is resumable exceptions. It has a nice geeky ring to it doesn't it? The first thing you might ask yourself is, "Why in the world would I want to resume an exception? It's an exception! Dead programs tell no tales!" True, true. Normally, you want an exception to send your program down in flames because you had a mechanical glitch that you didn't expect. Better stop everything before the propeller goes slashing through your data unkindly! But, what if we had exceptions that were good that could notify us of potential bad things or even enumerate potential bad things? Well, we do and we can! Smalltalk has a different take on exception handling. Much like a nuclear reaction in a controlled environment gives you energy, and mass destruction otherwise, Smalltalk allows us finer control over exceptions and what we can do with them like resuming. This is a powerful idea and it allows us to do unheard of feats in other languages especially when it comes to things like validation. For example, say we had the following code:
[self form validate]
on: ValidationException
do: [:exception | ^self informUser: 'Validation Failed: ', ex messageText].
self form save.

Pretty simple, right? Well, what if our form is very complicated and it's validation method looked like this:
validate
self name size > 25 ifTrue: [ValidationException signal: 'Name size > 25'].
(self email contains: $@) ifFalse: [ValidationException signal: 'Invalid Email'].

Pretty straight forward and under normal circumstances, our validation code will always signal on the first occurance it finds. Well, for the user it will get tiresome because it only points out each exception one at a time. The user will start to feel like Curly from The Three Stooges. And we don't want hairless users running around do we? Now, what if we could resume and just tabulate the validation exceptions and show them at once? No code changes in the form validation code, just in our handling of it. Well, we can do just that! Here's the new code:
[self form validate]
on: ValidationException
do:
[:exception |
validationMessages add: exception messageText.
exception resume].
validationMessages isEmpty ifFalse: [^self informUser: 'Validation Exceptions' messages: validationMessages].
self form save.

I left out some of the variable declarations to ease the readibility, but you get the gest of it. We now can resume on each occurance of the validation exception! Very cool! But, it doesn't stop there. We can return values from exception signals via resumes and this allows things like dynamic scope variables. Enjoy. Ruby's exceptions are resumable too. So, what are you waiting for? Go play!

1 comment:

Blaine Buxton said...

WoW...You're right. I stand corrected. I went looking around in the documentation and I don't know why I thought that! Oh well, I learned something new. Resumable Exceptions are tool in the good ole trick bag. You don't need them very often, but when you do, you really need them...=)