Piers Cawley <[EMAIL PROTECTED]> 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....