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