Hi all,

Patrick R. Michaud wrote:
On Fri, Jul 11, 2008 at 04:49:55PM -0400, Bob Rogers wrote:
Content-Description: message body text
   This is certainly not the case for recursive subs.  Consider the
attached example, a lightweight Perl 5 dumper.  (It is slightly
artificial to break the recursive step out into a sub, but that might
make sense after adding hash support.)  We need a distinct closure for each 
level of dump_thing call, lest $prefix refer to the wrong thing. And we need to 
call those closures from registers, to be sure that we are calling the right 
one.

In the attached example, I think the lines

    my $recur = sub {
        my $subthing = shift;
        
        dump_thing($subthing, $prefix.'   ');
    };

guarantee that $recur gets a distinct closure for each level
of call, since a closure is cloned upon assignment.  In other
words, the assignment is where a separate newclosure would be
performed (or, in my example, simply cloning the closure directly).

This is consistent with my view of the specified Perl 6 semantics[1] for closure handling. I translated Bob's Perl 5 example into PIR and put newclosure where the Perl 6 specification would suggest to put it and it produces the same output as the Perl 5 script. This is without doing *any* newclosure calls prior to a call, just some when we are taking a reference.

Pm: I hope the PIR helps you understand Bob's example better. Notice that we do newclosure whenever a block is referenced (where by block I mean anything compiled down to a Parrot .sub) and the reference contains the new closure, which makes sense because we're taking a closure (recording a snapshot of it at that point) to invoke later.

Bob: I hope this hand-compilation of your example with the Perl 6 semantics applied helps you see where Pm is coming from; happily, it also matches it's semantics when run in Perl 5. So I think we can make this example work just fine, without having to replace stuff in the symbol table (which is, well, awkward). How does it contrast with how you would have expected to compile this, and how does this approach fit with your HLL? Note that the code that I have attached runs and both with and without my previous patch that you started this thread about.

Note that this doesn't give any great answers yet about what happens when we do newclosure on a multi, but I think we can make that do something sane (snapshot the lot, perhaps? Need to think about what falls out of that...) Also it's interesting to note in this example that replacing "newclosure" with "clone" gives the same semantics.

Hope this helps the discussion,

Jonathan

[1] http://dev.perl.org/perl6/doc/design/syn/S04.html#When_is_a_closure_not_a_closure

.sub 'main' :main
    $P0 = new 'ResizablePMCArray'
    push $P0, 'a'
    $P1 = new 'ResizablePMCArray'
    $P2 = new 'ResizablePMCArray'
    push $P2, 'simple'
    push $P1, $P2
    push $P1, 'test'
    $P3 = new 'ResizablePMCArray'
    push $P3, 'for'
    push $P3, 'a'
    push $P3, 'simple'
    push $P1, $P3
    push $P0, $P1
    push $P0, 'script'
    'dump_thing'($P0, '#')
.end

.sub 'dump_thing'
    .param pmc thing
    .param pmc prefix
    .lex '$thing', thing
    .lex '$prefix', prefix

    $P0 = find_global 'anon_1'
    $P1 = newclosure $P0
    .lex '$recur', $P1
    
    $P2 = find_lex '$thing'
    $I0 = isa $P2, 'ResizablePMCArray'
    unless $I0 goto not_ResizablePMCArray

    $P3 = find_lex '$prefix'
    print $P3
    print "[\n"
    $P4 = find_global 'anon_2'
    $P5 = newclosure $P4
    $P6 = find_lex '$thing'
    'map'($P5, $P6)
    $P7 = find_lex '$prefix'
    print $P7
    print "]\n"
    goto end_if

  not_ResizablePMCArray:
    $P8 = find_lex '$prefix'
    print $P8
    $P9 = find_lex '$thing'
    print $P9
    print "\n"
  end_if:
.end

.sub 'anon_1' :outer('dump_thing')
    .param pmc subthing
    .lex '$subthing', subthing
    $P0 = find_lex '$subthing'
    $P1 = find_lex '$prefix'
    $P2 = new 'String'
    $P2 = concat $P1, '    '
   'dump_thing'($P0, $P2)
.end

.sub 'anon_2' :outer('dump_thing')
    .param pmc topic
    .lex "$_", topic
    $P0 = find_lex '$recur'
    $P1 = find_lex '$_'
    $P0($P1)
.end

.sub 'map'
    .param pmc block
    .param pmc array
    .local pmc result, it
    result = new 'ResizablePMCArray'
    it = iter array
    loop:
    unless it goto loop_end
    $P0 = shift it
    $P0 = block($P0)
    push result, $P0
    goto loop
    loop_end:
    .return (result)
.end

Reply via email to