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
|