Ken Fox <fox@mail.msen.com> 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.Thread Previous | Thread Next