Tail Call

Anthony Hannan ajh18 at cornell.edu
Fri Feb 1 17:58:32 UTC 2002


Scott A Crosby <crosby at qwes.math.cmu.edu> wrote:
> On Fri, 1 Feb 2002, Anthony Hannan wrote:
> > Tail call out of a block would be harder because the caller's receiver
> > (the block) (which we are replacing) holds the return context and
> > callee's (#bar) localReturns would have to be changed to a remoteReturns.
> > So a new method would have to be made on the fly and the receiver
> > would have to be wrapped in a new block closure with the return context.
> 
> Ah. Ha.. It took me two hours hours, but I think we're confusing two
> distinct things....
> 
> [ foo foo foo. ^self someMessage]
>       AND
> [ bar bar bar. self someMessage]
> 
> Which are *very very* different things.
> 
> What it means to 'tailcall' for the first seems messy. I don't know? Punt?
> Define some sort of new semantics for it? Use a normal method call? What
> do you think?

Tail call implementation for the first case is what I was describing
above and is messy.  I would just leave the normal call for this case.

> What it means to tailcall for the second is clear. A block returns the
> value of the last thing in the block, whether that is a value or a message
> send. If its a messagesend, it may be tailcalled, furthermore, there are
> no 'which context does it return into' issues. Finally, since we only care
> about the last method call, we're already done with using any variables in
> the context, We'll have popped any that we'll pass to the function we're
> invoking by this point, before we call out, so we can nuke the context
> (the one inside of [^^self bar]) safetly?

The second case is simple and is the same as a tail call in a regular
method.  Invoking a block that has no explicit returns (^) is equivalent
to invoking a method with the last expression returned.  But putting an
explicit return (^) in a block forces it to capture the home context and
will attempt to return to the home context's sender when the return is
interpreted.  [^self bar] would try to return to the home context's
sender (like in the first case above, which is messy to tail call).

Bijan Parsia <bparsia at email.unc.edu> wrote:
> Let me add a more informal, sloganny account of
> continuations: continuations are "dynamic" closures. That is, just as
> closures "close over" the lexical environment,  continuations "close
> over" the *invoking* environment (the analogy is with dynamic scoping of
> variables). By "freezing" a copy of the calling stack, continuations 
> let you "continue" the compuation from that point any number of
> times.

We could add a method to BlockClosure called #copyStack that will copy
its home context call stack.  This way everytime you want to use it as a
continuation that may be used again you call this first.  We can even
have an #asContinuation method that would wrap the block closure in a
Continuation object that when invoked would send #copyStack to the block
closure first.  Note: "closure" continuations are only applicable to
blocks having explicit returns (capturing their home context).  A block
closure without an explicit return is just a regular object (holding
captured temp values) with an extra instance-specific method that is
invoked via #value...

Cheers,
Anthony

PS. Thanks guys for the in-depth descriptions of continuations.



More information about the Squeak-dev mailing list