Ah Ha!
Continuations…frequently referred to by Paul Graham as, to paraphrase, awesome. With all the reading I've done regarding continuations, I've never really seen the big deal about them. Turns out its because I didn't get it. Imagine that… Fortunately for me, I have continued to read about them and finally had the "ah ha" moment. Reading this page describing fuctional programming, the author explains continuations in way that finally made it click:
A "continuation" is a parameter we may choose to pass to our function that specifies where the function should return. The description may be more complicated than it sounds. Take a look at the following code:
int i = add(5, 10); int j = square(i);The function add returns 15 to be assigned to i, the place where add was originally called. After that the value of i is used to call square. Note that a lazy compiler can't rearrange these lines of code because the second line depends on successful evaluation of the first. We can rewrite this code block using Continuation Passing Style or CPS, where the function add doesn't return to the original caller but instead returns its result to square.
int j = add(5, 10, square);In this case add gets another parameter - a function that add must call with its result upon completion. In this case square is a continuation of add. In both cases j will equal 225.
So if you redefine your functions to take an optional last parameter that points to where the function should return to, suddenly you have some serious flexibility regarding what happens at the end of functions. The brilliance behind this method is shown a little further in the article:
Once we convert a program to CPS it becomes clear that every instruction has some continuation, a function it will call with the result, which in a regular program would be a place it must return to. Let's pick any instruction from above code, say add(5, 10). In a program written in CPS style it's clear what add's continuation is - it's a function that add calls once it's done. But what is it in a non-CPS program? We could, of course, convert the program to CPS, but do we have to? It turns out that we don't. Look carefully at our CPS conversion. If you try to write a compiler for it and think about it long enough you'll realize that the CPS version needs no stack! No function ever "returns" in the traditional sense, it just calls another function with the result instead. We don't need to push function arguments on the stack with every call and then pop them back, we can simply store them in some block of memory and use a jump instruction instead. We'll never need the original arguments - they'll never be used again since no function ever returns! So, programs written in CPS style have no stack but have an extra argument with a function to call. Programs not written in CPS style have no argument with a function to call, but have the stack instead. What does the stack contain? Simply the arguments, and a pointer to memory where the function should return. Do you see a light bulb? The stack simply contains continuation information! The pointer to the return instruction in the stack is essentially the same thing as the function to call in CPS programs! If you wanted to find out what continuation for add(5, 10) is, you'd simply have to examine the stack at the point of its execution!
Continuations are particularly well-suited to web programming because of the stateless nature of the web. A request for a page could come at anytime, and what happened before that page request will not matter. However, this is not always desirable. With continuations, we can simulate state, even in a stateless environment. For more on that subject, start with this article. An interesting alternative to MVC. This is a whole new paradigm from the one I was taught in school and I think rightfully so. It is a tough concept to wrap your mind around at first. Now that I've had the "ah ha" moment, I look forward to implementing these ideas in my future work.