[Python-Dev] A "real" continuation example

Tim Peters tim_one at email.msn.com
Fri May 21 00:04:04 CEST 1999


[Tim]
> So what would this look like in Continuation Python?

[Sam]
> Here's my first hack at it.  Most likely wrong.  It is
> REALLY HARD to do this without having the feature to play with.

[Skip]
> The thought that it's unlikely one could arrive at a reasonable
> approximation of a correct solution for such a small problem without the
> ability to "play with" it is sort of scary.

Yes it is.  But while the problem is small, it's not easy, and only the Icon
solution wrote itself (not a surprise -- Icon was designed for expressing
this kind of algorithm, and the entire language is actually warped towards
it).  My first stab at the Python stack-fiddling solution had bugs too, but
I conveniently didn't post that <wink>.

After studying Sam's code, I expect it *would* work as written, so it's a
decent bet that it's a reasonable approximation to a correct solution as-is.

A different Python approach using threads can be built using

    Demo/threads/Generator.py

from the source distribution.  To make that a fair comparison, I would have
to post the supporting machinery from Generator.py too -- and we can ask
Guido whether Generator.py worked right the first time he tried it <wink>.

The continuation solution is subtle, requiring real expertise; but the
threads solution doesn't fare any better on that count (building the support
machinery with threads is also a baffler if you don't have thread
expertise).  If we threw Python metaclasses into the pot too, they'd be a
third kind of nightmare for the non-expert.

So, if you're faced with this kind of task, there's simply no easy way to
get it done.  Thread- and (it appears) continuation- based machinery can be
crafted once by an expert, then packaged into an easy-to-use protocol for
non-experts.

All in all, I view continuations as a feature most people should actively
avoid!  I think it has that status in Scheme too (e.g., the famed Schemer's
SICP textbook doesn't even mention call/cc).  Its real value (if any <wink>)
is as a Big Invisible Hammer for certified wizards.  Where call_cc leaks
into the user's view of the world I'd try to hide it; e.g., where Sam has

    def walk (self, x):
        if type(x) == type([]):
            for item in x:
                self.walk (item)
        else:
            self.item = x
            # call self.suspend() with a continuation
            # that will continue walking the tree
            call_cc (self.suspend)

I'd do

    def walk(self, x):
        if type(x) == type([]):
            for item in x:
                self.walk(item)
        else:
            self.put(x)

where "put" is inherited from the base class (part of the protocol) and
hides the call_cc business.  Do enough of this, and we'll rediscover why
Scheme demands that tail calls not push a new stack frame <0.9 wink>.

the-tradeoffs-are-murky-ly y'rs  - tim






More information about the Python-Dev mailing list