From: "Patrick R. Michaud" <[EMAIL PROTECTED]>
   Date: Fri, 11 Jul 2008 01:55:11 -0500

   On Thu, Jul 10, 2008 at 11:06:55PM -0500, Patrick R. Michaud wrote:
   > 
   > I _think_ [methods and subs] are the only two cases where we 
   > have to do something like this, and I guess they aren't too onerous.  

   I was wrong, the third case is MultiSubs, and at the moment
   it's _very_ onerous, because we can't just replace things in 
   the symbol table.

Yes, I think we are stuck with that for now.

   But having given myself permission to take a break, I think I may
   have come up with a workable answer that does almost everything
   we (both) want . . .

   If I understand your messages correctly, the main problem with
   "autoclosures" is the "auto" portion -- i.e., trying to capture
   variable bindings automatically at the time a closure is invoked, 
   and doing this only once on the closure's first invocation.  
   Let's agree that this behavior is wrong.

No dissent here.

   Let's go even further and explicitly make this an error, such that
   invoking a Closure PMC where its outer_ctx is null throws an 
   exception.  

You are preaching to the choir.  ;-}

   However, I'd still like the capability to give an existing Closure
   an outer_ctx without having to replace it in the symbol table,
   method table, or MultiSub PMC . . .

   To repeat, in this scenario, invocation never does a capture on its
   own -- that's always up to the outer sub to handle by doing either
   a newclosure or capture operation prior to invocation.

I think this sounds like a good thing.  However, there is a further
problem with "autoclose" that had completely slipped my mind [1]:  The
"autoclose" feature assumes that there will only ever be one active
closure at a time for a given sub.  This is a pretty serious limitation,
and I apologize for not mentioning it sooner.

   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.

   So that takes us back to what I said about considering "autoclose" as
an optimization, to be used only if the compiler can prove that it is
safe.  And since it can be difficult to prove that a sub is not
recursive (since it may recur mutually with a sub in another compilation
unit), and impossible to prove that it won't be invoked re-entrantly
from another thread, I have to conclude that "autoclose" is a solution
in search of a problem.  (So Leo's and chromatic's instincts prove to be
correct.)

   Unfortunately, this hits squarely at the heart of your desire not to
re-install a new closure in the namespace (when the sub has to be
invokable that way).  It may still make sense to make incremental
improvements to autoclose, but if I were in your shoes, I would remove
all use of autoclose from PCT and Rakudo, replacing it with a general
solution, and reintroduce it carefully only when both were closer to
production and speed is important.

   . . .

   Instead of having Parrot do autoclosures -- i.e., automatically
   capture outer_ctx when an inner Closure is invoked -- perhaps
   we could have a way for an outer sub to automatically perform
   the captures for all of its inner subs.  In other words, every
   sub would maintain a list of its inner subs (automatically
   created from the inner subs' :outer flags), and then the
   outer sub can automatically set the outer_ctx for all of
   its inner closures.  This could happen either as part of
   the outer sub's invocation, or it could be an explicit
   instruction or method call generated by the HLL compiler.

How about putting an :auto pragma on the inner subs?  That would allow
it to be done transparently in C as part of sub calling, and would give
a fairly fine degree of control to the compiler.  (Assuming we want to
keep drinking this Kool-Aid, that is.  ;-)

   Based on what Bob has been saying, I can't now think of a case where
   an inner closure _shouldn't_ go ahead and have its outer_ctx set
   whenever an outer sub is invoked . . .

<honk>Foul!</honk> That's exactly what r28763 does to break my code.
(Not to mention the attached example.  ;-)  But I won't make you sit in
the penalty box; it's just too damn hard to keep all this in one's head
at the same time.

                                        -- Bob

[1]  The fact that my mind has been foggy with headaches on and off for
     the past three days probably has something to do with it.

#! /usr/bin/perl -w

use strict;
use warnings;

sub dump_thing {
    my ($thing, $prefix) = @_;

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

    if (ref($thing) eq 'ARRAY') {
        print($prefix, "[\n");
        map {
            $recur->($_);
        } @$thing;
        print($prefix, "]\n");
    }
    else {
        print "$prefix$thing\n";
    }
}

dump_thing([qw(a), [['simple'], 'test', [qw(for a simple)]], 'script'],
           '# ');

Reply via email to