From: chromatic <[EMAIL PROTECTED]>
   Date: Wed, 9 Jul 2008 13:59:16 -0700

   I read that in the lexicals PDD, and I think the current behavior is
   bizarre *without* the call to newclosure.  How is it even possible to
   close over a lexical environment in an outer when that lexical
   environment was never even created?

   It's difficult to describe that as anything other than ridiculous.

That was my initial reaction, too . . .

   Consider Bob's example Perl 5 code:

           sub outer {
               my $x = shift;

               print "outer foo $x\n";

               sub inner {
                   print "inner foo $x\n";
               }
           }

           # Note that it is not illegal to call inner before outer.
           inner();

   There's a compile-time warning here, namely that $x will not stay
   shared.  Even though it looks like inner() should close over
   outer()'s $x per Perl 5's scoping rules (ignoring that you can't nest
   subs in Perl 5), there is no $x available at the call to inner().

Yes.  I would not want Perl 5 code like that in *my* repository. ;-}

   If you wrote this instead:

           sub outer {
                   my $x = shift;

                   print "outer foo $x\n";

                   return sub {
                           print "inner foo $x\n";
                   }
           }

           my $inner = outer( 10 );
           $inner->();

   ... then Perl 5 effectively performs a newclosure action, attaching
   the active lexpad to the new instance of the subroutine reference.

Yes.  And if you want to preserve the external API, you could even do
something like

            *inner = sub {
                print "inner foo $x\n";
            };

which requires 'no strict', but (a) avoids the "not stay shared" warning
and (b) updates inner() every time outer() is called, as Patrick wants
in PIR.  (IMHO, this is what your example *should* mean.)

   I suspect the motivation for the bizarreness of the specification is the 
   desire to make code like this work in Parrot:

           {
                   my $x;

                   sub set_x { $x = shift }
                   sub get_x { return $x }
           }

   ... except that there's no real way in Parrot right now to create an
   enclosing lexical block, activate it, and attach it as the outer to
   one or more Closures.

   -- c

FWIW, I don't consider this bizarre; I've seen production code that does
just this in order to share internal state between API functions.  What
would be bizarre is expecting set_x or get_x to be able to do anything
meaningful before the outer block is executed.

   And it does work now, albeit with a little indirection; see
bank-account.pir, attached.  Or do you not consider this a "real way"?

   At any rate, Leo said [1] that "autoclose" was something Audrey
wanted, so I assumed it was here to stay.  I'd just like to keep it from
spreading.  ;-}

                                        -- Bob

[1]  
http://groups.google.com/group/perl.perl6.internals/browse_thread/thread/41dbfee7b7b5bbe7

.namespace ['Foo']

.sub outer
        .local pmc x
        .lex '$x' ,x
        .const .Sub setter = 'raw_set_x'
        setter = newclosure setter
        set_hll_global ['Foo'], 'set_x', setter
        .const .Sub getter = 'raw_get_x'
        getter = newclosure getter
        set_hll_global ['Foo'], 'get_x', getter
.end

.sub raw_set_x :outer('outer')
        .param pmc new_x
        store_lex '$x', new_x
        .return (new_x)
.end

.sub raw_get_x :outer('outer')
        .local pmc new_x
        new_x = find_lex '$x'
        .return (new_x)
.end

.sub init :init
        outer()
.end

.sub main :main
        set_x(1)
        $P0 = get_x()
        print $P0
        print "\n"
        set_x(9)
        $P0 = get_x()
        print $P0
        print "\n"
.end

Reply via email to