On Sat, Feb 12, 2005 at 03:55:40PM -0500, Uri Guttman wrote:
:   LW> What's going on here is that the loop body is a closure that is
:   LW> cloned upon entry to the loop (you're logically passing a closure
:   LW> to the "for()" function that implements the loop), so if there's a
:   LW> FIRST inside, it runs each time the loop is initialized.  Likewise
:   LW> state variables are logically regenerated for closure clones, so if
:   LW> use_first() above wants to have a state variable that is maintained
:   LW> from call to call, it must put it *outside* the loop.
: 
: i am not clear on the actual answer. my take on what you said is that i
: was right, FIRST will execute at the beginning of each time the loop is
: entered which is what joe wants. am i correct?

Yes.

:   LW> Also, note that a LAST block, if any, has to be called from within
:   LW> the implementation of for(), since only for() knows when it's done
:   LW> with the loop as a whole.
: 
: similarly for FIRST as only for() knows when it starts up the loop again
: and reinitializes the counter.

I think FIRST initialization happens automatically based on the cloning
mechanism, and the fact that FIRST knows when it's first already.  The
code of a FIRST can actually be called inline, I think.  Could be wrong
about that.

:   LW> It will be an interesting problem for the optimizer to figure out
:   LW> how to avoid cloning closures that are passed only to synchronous
:   LW> loop-controller functions such as for() and not otherwise used
:   LW> asynchronously.  Perhaps the signature of for() can make some
:   LW> guarantees about not squirreling away the closure pointer in
:   LW> some weird place.  This is perhaps related to the issue of timely
:   LW> GC on pointers you know haven't been copied into outside storage.
: 
: i see the problem. if the loop body refers to lexicals declared outside
: it, it looks like a classic perl5 closure and would need to be
: cloned. what about the fact that for() will be called in effectively a
: void context? a classic closure makes sense only when the code ref is
: saved or possible called immediately via (p5) ->. for() is called
: immediately but with a different signature as you said. the void context
: would help the optimizer since you don't save the code block for later
: reuse, no cloning should be done.

Doesn't really help--when you think about it, the block you pass to
map or grep is also a loop block, and those generally aren't used in
void context.  It would have to be a marker on the actual block argument
in the signature.  Maybe based on type:

    sub mygrep (Block &block, [EMAIL PROTECTED]) {...}  # don't clone
    sub mysched (Closure &block, [EMAIL PROTECTED]) {...}       # clone

Since the Block declaration would mostly be an optimizer hint,
I suspect the default should be to clone, so the latter can just
be written:

    sub mysched (&block, [EMAIL PROTECTED]) {...}               # clone

Actual type names are negotiable, of course.  Maybe typename is the
wrong place for that info, and it should just be

    sub mygrep (&block is uncloned, [EMAIL PROTECTED]) {...}    # don't clone

Or maybe it's just spelled with existing props:

    sub mygrep (&block is ref, [EMAIL PROTECTED]) {...} # don't clone
    sub mygrep (&block is copy, [EMAIL PROTECTED]) {...}        # clone 
(default)

Larry

Reply via email to