From: "Patrick R. Michaud" <[EMAIL PROTECTED]>
   Date: Fri, 3 Aug 2007 21:51:53 -0500

   Perhaps ignore my earlier message -- this one is more coherent.

I haven't gotten that one yet.  (Must have been via RT.  Now if I could
only remember to send all my incoherent posts via RT.  ;-)

   On Fri, Aug 03, 2007 at 03:37:39PM -0700, Bob Rogers wrote:
   >    sub make_closures_loop {
   >        # Return $n closures, each with lexical references to $i and $n.
   >        my $n = shift;
   > 
   >        my @result;
   >        for (1..$n) {
   >            my $i = $_;
   >            push(@result, sub { print "Called sub $i out of $n.\n"; });
   >        }
   >        return @result;
   >    }
   > 
   >    Currently, the only way to get a distinct binding for each "$i" in
   > PIR is to factor the loop body out into a separate lexical sub.  This is
   > far from ideal, not least because it is not transparent to the HLL user.

   Factoring the loop body out into a separate lexical sub is _exactly_
   how Chip described to me that the above needed to be done.
   Or, phrased differently, every lexical scope ends up requiring
   its own parrot sub . . .

Bummer.

   I'm not sure why this separate lexical sub has to be visible
   to the HLL user -- the compiler ought to be able to make it appear
   as though the sub isn't present.  (But I also bet that we can
   come up with an example that makes it really hard to do that.)

It will show up in backtraces, if nothing else.  This may complicate the
user's debugging session slightly, because what the user assumed would
be one call frame is actually two, and inner functions may not have the
expected compiler-assigned names, but that's hardly a show-stopper.

   >    Parrot should do better, IMHO.  The easiest way, it seems, would be
   > to resurrect the push_pad and pop_pad instructions in some form.  [...]

   I'd like for Parrot to be able to do better, yes, but I'm not
   yet enough of an expert on closure handling to be able to
   refute Chip's reasons for designing things this way.

The current model has the advantage of being more declarative, which is
good; things that can be nailed down at compile time should be.  But the
same thing could be done for multiple loop scopes as well.  Consider the
following alternative:

        ## Return n closures, each with lexical references to "I" and "N'.
        .sub make_closures_loop
                .param pmc n
                .lex "$n", n
                .local pmc result
                result = new .FixedPMCArray
                $I1 = n
                result = $I1
                .const .Sub $P53 = 'internal_make_closures_loop_0'
                $I0 = 0
        next:
                if $I0 >= $I1 goto done
                .push_scope
                .lex "$i", $P42
                $P42 = new .Integer
                $P42 = $I0
                inc $P42
                newclosure $P52, $P53
                result[$I0] = $P52
                inc $I0
                .pop_scope
                goto next
        done:
                .return (result)
        .end

Every .lex belongs to the immediately enclosing .push_scope/.pop_scope
group (or the sub top-level scope).  .push_scope needs to expand into
push_pad, and .pop_scope needs to do a pop_pad, but the pseudo-ops serve
to delimit scopes so that the PIR compiler can build a LexInfo object
for each scope.  (But the inner ".lex" ops may require an explicit
store_lex, since they are not being stored in the Parrot_Context.
(Which is a good thing.))

   I also found the push_pad and pop_pad model somewhat easier to grasp
   conceptually, but I recall Chip was fairly certain that they wouldn't
   handle things in the generic case.

They would certainly permit more to be handled than is handled now.  And
re-adding them should be monotonic in terms of Parrot functionality.
Which means that Chip's statement (IYRC) seems to make no sense.  ???

   FWIW, the perl6 compiler currently treats _every_ block as a new 
   lexical scope, and generates a separate Parrot sub for each . . .

Hmm.  The "lexical scope == Parrot sub" worldview seems backwards to me.
But probably I'm just grumbling because I've realized I'm going to have
to rewrite a fair-sized chunk of my compiler to cope with this.  Oh,
well; so be it.

   ================
   From: "Patrick R. Michaud" <[EMAIL PROTECTED]>
   Date: Fri, 3 Aug 2007 22:13:25 -0500

   Just for completeness, attached is a PIR version that I think
   is slightly more faithful to the original test-closures.pl 
   program.  It appears to work:

     $ ./parrot test-closures-3.pir
     Called sub 1 out of 3.
     Called sub 2 out of 3.
     Called sub 3 out of 3.
     $

   Pm

Makes sense; looks like what "map" would compile into, if the block were
not inlined.

   Thanks for explaining the situation.

                                        -- Bob

Reply via email to