Categories
java lisp ruby

Continuations and Exceptions

I very often find myself tripping over ‘old’ ideas in software technology and discovering a rich topic that I had no idea even existed. This weeks elephant in the room is the ‘Continuation’ language/compiler feature.

Let’s take a quick look at a simplified version of an example of a continuation that I found to illustrate the point.


irb(main):041:0> def ab
irb(main):042:1>    puts "a"
irb(main):043:1>    callcc { |continuation| return continuation }
irb(main):044:1>    puts "b"
irb(main):045:1> end
=> nil
irb(main):046:0> x = ab()
a
=> #<Continuation:0xb7c5ee84>
irb(main):047:0> x.call()
b
=> nil

The callcc function accepts a closure as an argument. This closure accepts the ‘continuation’ and we immediately return it from the function. The continuation contains all of the state that got us to the point before we exit, variables, stack-frames, the lot. The key is that the continuation is itself a closure and when it is called the code will continue from the next line. I think it’s easy to see that this feature has pitfalls. It’s like a GOTO but without the benefit of having a line number to lookup! This is because on the outside every continuation looks pretty much the same. But this approach does have arguably real tangible benefits in Web servers like Seaside.

So what?

Well it turns out that exceptions in C++ derivative languages are a stupider half-cousin of continuations called: escape continuations. Thinking about it the similarity is striking and not all that surprising. The reason I say they’re stupid though is because exception objects are not re-entrant in the same way as continuations are, and the context that is captured from the exception is defined by the programmer. However, it’s plain to see that the exception handling we have in most modern programming languages like C++, Java, C#, etc are a diluted form of continuation.

So what?

Well I’m not totally convinced of the practicality of continuations in web programming environments, partly because I’m a bit old-school when it comes to performance and those languages that have web-frameworks and support continuations (Smalltalk, Ruby, PHP) are slow-as-molasses. The other reason I’m not keen on the idea of continuations is the practicality of working with them, i.e. they are a variation on the GOTO in that it’s very hard to follow the flow of the program by just looking at it and reading it. But I know that one day I will discover the need to make sparing use of a continuation and be glad that I knew that I could do it.

If the truth is ever told, I think exceptions suffer from the curse of the GOTO as well. And I think the reason for that is partly because the exception mechanism as implemented in Java, C# and C++ is a teensy bit broken. The reason, again, is that the flow of control jumps up the stack to a potentially unknown place. I say unknown because if you write a library that throws an exception and after you release it you change the contract of how that exception is thrown, well then you’re in trouble.

Trouble, that’s what

The catching of exceptions is based on type, and inheritance rules apply, so the inheritance hierarchy of the exception classes you use affects the flow of control. This is clearly the intention since you use the type to differentiate a NullArgumentException and a NullPointerException and how you deal with these will probably require different code. However, if the handling code was the same well then I why couldn’t I catch the base class instead and have one code-block? This is the temptation and the danger because if someone else decides to rejig the exception hierarchy you might not catch the exception you want. Worse still, you might end up catching exceptions you don’t expect and providing incorrect handling code for them.

So what?

Well like Peter Parker says:

Whatever life holds in store for me, I will never forget these words: “With great power comes great responsibility.” This is my gift, my curse. Who am I? I’m Spider-man.

And whilst we may not be Spidey we need to recognize the gifts and curses that 50 years of programming languages has given us … oh, and we should take note about the power/responsibility thing too …

One reply on “Continuations and Exceptions”

Regarding continuations in web programming making it more difficult to follow the flow of the application, I think it’s quite the opposite. The idea with using continuations is to keep the code flowing linearly, instead of having a big CASE statement at the top of your application which then does a GOTO the next part of the program.

I cite Perl’s Continuity library (of which I am the author and thus am quite biased towards), I can write:

my $a = prompt(“Enter a number”);
my $b = prompt(“Enter another number”);
display(“The sum of $a and $b is ” . ($a + $b));

Where each call to “prompt” displays an appropriate prompt page, waits for input, and then returns the result. If you were to write this simple program in a traditional way you’d quite likely keep some sort of a “current_step” variable which indicated if we were asking for the first number, asking for the second, or displaying the third. Each step would indicate what the next step of the application is supposed to be, thereby implementing an ad-hoc state machine.

Scalability, however, is definately an issue 🙂

(email me if you want the complete source code for this example, awwaiid@thelackthereof.org).

Comments are closed.