[Python-Dev] uthread strawman

Tim Peters tim.one@home.com
Thu, 9 Nov 2000 03:44:07 -0500


[Guido]

[examples of presumably fuzzy semantics in the presence of continuations]

> ...
> But now consider this:  the "evaluation stack" contained in each
> frame could easily be replaced by a bunch of temporary variables,
> if we had a slightly different instruction set ...
> Then would we save those temporary variables or not?

Yes, provided they remained anonymous (to the user) they're simply internal
implementation details, and continuations preserve all things "like that".
It's only visible name bindings that continuations let change across
resumptions.

> it can make a difference!

Indeed yes.

> ...
> But if the compiler were to use temporary variables instead of the
> evaluation stack, they might not have been restored!

The technical term for that would be "bug" <0.5 wink>.

Christian already covered the for-loop example.  A more interesting
variation is a for loop without a named "indexing vrbl":

    for x in sequence:
        etc

Scheme has nothing direct to say about this because Scheme has no loops.
Writing it as a recursive function instead leads to the same kind of result,
though.

> ...
> This semantic imprecision is one of the reasons why I don't like the
> concept of continuations.

It's clearer in Scheme because Scheme has fewer "primitive concepts" than
Python.

> (I've been told that the exact semantics of continuations in Scheme
> differ greatly between Scheme implementations.)

I believe you've been told that, but not by a clueful Scheme user!
Continuations are rigorously well-defined in Scheme.  What *isn't*
well-defined in Scheme is order of evaluation in many cases, so an
expression like

   (+ (f) (g))

can display wildly different behavior across implementations if one or both
of the functions {f, g}, directly or indirectly, creates or invokes a
continuation (say that g does:  it's not defined whether f has been invoked
by the time g is -- indeed, it's even OK to invoke f and g in parallel).

Note:  the Python eye sees something like that and leaps to the rule "OK,
chowderhead, so don't muck with continuations in the middle of
expressions!".  What that misses is that *everything* in Scheme is "an
expression".  Scheme implementations do "differ greatly" in *this* respect.
BTW, note that Scheme implementations can also display wildly different
behavior if f and g merely have side effects (i.e., this really has nothing
to do with continuations specifically:  they're just another form of
side-effect you can't always predict without knowing the order of evaluation
first).

[skipping the proposal because we talked about it instead]

[Gordon McMillan]
> ...
> [About continuations: while I love the fact that Christian has made
> these available for playing, I have so far not found them productive. I
> wrote a simple minded backtracking parser using them, but found it no
> better than a coroutine based one. But I am interested in how a *real*
> pervert (eg, Tim) feels about it - and no "Gee, that sounds like a *good*
> idea, boss", please.]

I don't know of any comprehensible application of continuations that can't
be done without them.  The real appeal of continuations is in their
theoretical elegance (they're a single mechanism that can be used to build
all sorts of stuff, much as all of "if" and "while" and "for" can be built
out of compares and gotos -- continuations can be used to implement all of
calls, non-resumable and resumable exceptions, generators, coroutines,
non-deterministic evaluation, "thread like" stuff, ...).  In any specific
case, though, you want to live at the higher level, not at the raw
continuation level.

WRT a backtracking parser, note that this is what Icon *lives for*, and
generators alone suffice (and are indeed very pleasant) for natural
expression of that task.  Icon became what it is when Griswold decided to
open up the backtracking pattern-matching engine underlying SNOBOL4, and
make it the basis for all expression evaluation.  It took him 3 full
languages (SL5 and Rebus came before Icon) and 20 years to get this right.

Building a backtracking parser directly out of continuations sounds to me
mostly painful.  Building generators out of continuations *is* painful (I've
done it).  Curiously, the symmetry of coroutines appears to make building
them out of continuations easier (than building generators).

I'm not in love w/ continuations:  I *could* be if Guido got Continuation
Religion and wanted to redo exceptions and calls on top of continuations
too, but given that whatever happens here is destined (Christian will say
"doomed" <wink>) to co-exist with everything that's already here, the appeal
of continuations is minimal.  I've got no desire to play with novel new
control structures in Python (note that I don't consider generators-- or
even coroutines --to be "novel", not after they've been in multiple
languages for more than 30 years), and Python doesn't have the syntactic
flexibility that makes such experiments *pleasant* in Scheme anyway.  So
it's enough for me if Python supports the handful of new control-flow
gimmicks (generators, coroutines, maybe uthreads) tasteful *users* ask for;
if we don't need continuations for those, fine by me.  BTW, I'd also like to
pickle a pure-Python computation in mid-stream, save it to disk, and resume
it later after a reboot (or on another machine!); we don't need
continuations for that either (although we do need much of what Stackless
does).

switching-from-redefining-truth-to-redefining-falsehood-ly y'rs  - tim