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.