Piers Cawley <pdcawley@iterative-software.com> wrote: > > { > > my $x = "bar"; > > sub foo { > > # $x # <- uncommenting this line changes the outcome > > return sub {$x}; > > } > > } > > print foo()->(); > > Well, I would expect it to output 'foo' on both occasions, and I'm > more than a little surprised to discover that it doesn't. Looks like a > bug to me. Using the notation $outer:x, $foo:x and $anon:x to refer to whatever $x might be in the 3 scopes: With the $x: foo() is a closure created at compile time. By the time the main {} block has been executed (but before foo() is called), the $outer:x is undef, and $foo:x is 'bar' (standard closure stuff). When foo() is executed, the anon sub is cloned, and at that time, $anon:x is set from from foo's pad, so it gets 'bar'. Without the $x: foo is no longer a closure - ie it doesnt have a private copy of $x in its pad. At cloning time, sub {$x} picks up its value of $x from $outer:x, since there isn't a $x in foo's pad - thus it picks up 'undef' from $outer:x that went out of scope a while ago. If there was an explicit declaration that your were closing (is that the right verb?), it might be clearer to the user what what going on. { my $x = "bar"; sub foo { # my outer $x; # <- uncommenting this line changes the outcome return sub {my outer $x}; } } print foo()->(); (I've changed 'closure' to 'outer' since John Porter's just pointed out to me privately that 'closure' is grammatical nonsense) Or to put it all another way.... Any bare use of a lexical in an inner sub, such as "$x" is roughly equivalent to my $x = copy_of_the_value_at_compile_or_clone_time_of_the_outer($x); so a bare '$x' has the combined implicit actions of creating a new $x for the current scope (or even till the end of the current sub), and initialising to a partiular value at a particular time. That's quite a lot of semantic baggage attached to an innocent bare var! So instead, I'd like "$x" to be an error, and "my outer $x" to be shorthand for my $x = copy_of_the_value_at_compile_or_clone_time_of_the_outer($x); But I can see I'm not on to a winner here....Thread Previous | Thread Next