When an eval
statement is within the scope of a lexical variable, that variable should be within the lexical context of the evaluated block. Moreover, lexical variables should be available in the lexical context of subs.
Yet this doesn't work:
use warnings;
{
package VLE;
my $ln10 = 2.302585092994045684017991454684;
sub reval {
say eval $_[0] if @_;
}
}
package VLE;
reval( q($ln10) );
It results in:
Variable "$ln10" is not available at (eval 1) line 1.
But if I (uselessly) use the lexical variable anywhere in the block, it's suddenly available in the eval:
use warnings;
{
package VLE;
my $ln10 = 2.302585092994045684017991454684;
sub reval {
say eval $_[0] if @_;
my (undef) = $ln10;
return 0
}
}
package VLE;
reval( q($ln10) );
prints
2.30258509299405
Why does this happen?
The destruction of references isn't the issue, since this code (which maintains a reference to $ln10
) also fails:
use warnings;
{
package VLE;
my $ln10 = 2.302585092994045684017991454684;
sub reval2 {
say eval $_[0] if @_;
my (undef) = $ln10;
return 0
}
sub reval {
say eval $_[0] if @_;
return 0
}
}
package VLE;
reval( q($ln10) ); # still fails
reval2( q($ln10) ); # works
A subroutine does not close over (capture) all visible lexical variables, but only those that are referred to within the subroutine body. This is a pretty integral part for reference counting to work properly. Which variables are captured is determined at compile time, and the variables are captured when the subroutine definition is executed (compile time for named subs, run time for anonymous subs).
Here your first reval
does not capture the $ln10
variable. Therefore, it is not available inside the eval. Because the eval string is a runtime value, it cannot be taken into account when determining which variables should be captured.
More precisely, the $ln10
variable is destroyed when the enclosing block is left, because no further references to it exist. So this code would work because the $ln10
variable still exists while the eval is executed:
use warnings;
{
package VLE;
my $ln10 = 2.302585092994045684017991454684;
sub reval {
say eval $_[0] if @_;
}
reval(q($ln10));
# $ln10 variable exists until here
}
The second eval
does capture the variable so its lifetime is extended until the point in time where the eval is executed, and everything works as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With