Ken Fox <[EMAIL PROTECTED]> wrote:
> We must be very careful not to confuse "closure" with "Perl's
> current implementation of closure". You've stumbled onto a bug in
> Perl, not discovered a feature of closures. Perl's "closures"
> were horribly buggy until release 5.004. (Thanks Chip!)

Er, no its not a bug - or at least Gurusamy didnt think so.

> Closed variables are just local variables. There's nothing special
> about refering to a variable from an inner scope. You don't want
> to write
> 
>   sub foo {
>     my $x;
> 
>     if (...) { my outer $x; $x = 0 }
>     else     { my outer $x; $x = 1 }
> 
>     $x;
>   }
> 
> do you? So why make people using closures do it?

The whole point is that closed variables *aren't* 'just local variables'.
The inner $x's in the following 2 lines are vastly different:

sub foo { my $x= ...     { $x } ....}
sub foo { my $x= ... sub { $x } ....}

In the first line, the two $x's both refer to the same thing. In the
second line, they don't. To all intents and puposes the inner $x in the
2nd line is declaring a new lexical which happens to grab the outer $x's
value at the time the anon sub is instantiated.

The reason why removing the 'middle' $x in the following

{ my $x = 'bar'; sub foo { $x; sub {$x} }}

causes the behaviour to change is that the middle $x implicitly gives
foo() a copy of $x at compile time. When the anon sub is cloned,
it picks up the current value of foo()'s $x. Without the middle $x, the
cloned sub picks up the outer $x instead.

Since the use of a bare lexical in a nested sub to all intents and purposes
introduces new variable, I thought it would help *people* for this to
be explicitly shown. It would also resolve some fuzzy scoping issues
by making things explicit. In the following, should the anon sub grab
foo()'s $x or the outer $x ?

{ my $x = 'bar'; sub foo {  {$x}; sub {$x}  }}

In bleedperl, the outer $x is grabbed, while the following line causes
foo()'s $x to be grabbed:

{ my $x = 'bar'; sub foo {  sub {$x}; {$x}  }}

Clearly one of them is a bug, but which one? No one on P5Pers seemed to want
to decide.

Use of an 'outer' declaration would make this explicit:

{ my $x = 'bar'; sub foo {  outer $x;  sub {$x} } # grab foo's $x
{ my $x = 'bar'; sub foo { {outer $x;} sub {$x} } # grab outer $x

Dave "monomania" M.

Reply via email to