can anyone explain to me why a variable that is declared in package can not be accessed by eval function unless it is used one time inside a sub?
(perl v5.16.3 MSWin32-x64-multi-thread ActiveState)
Package:
use strict;
use warnings;
package testPackage;
my $insertVar = "TEST";
sub testSub {
my $class = shift;
my $test = shift;
eval '$test="'.$test.'";';
return $test;
}
1;
Program:
use strict ;
use warnings ;
use testPackage ;
my $testVar = q[insertVar = ${insertVar}] ;
$testVar = testPackage->testSub( $testVar ) ;
print "$testVar\n" ;
Result when executing program:
Use of uninitialized value $insertVar in concatenation (.) or string at (eval 1) line 1. insertVar =
Now if I use the variable inside testSub (by e.g. printing it):
use strict;
use warnings;
package testPackage;
my $insertVar = "TEST";
sub testSub {
my $class = shift;
my $test = shift;
print $insertVar . "\n";
eval '$test="'.$test.'";';
return $test;
}
1;
Then the program runs exactly as I intended:
TEST
insertVar = TEST
my
variables declared in a file (outside of curlies) go out of scope when the file finishes executing (before require
and use
return).
$insertVar
will only continue to exist after the file has finished executing it if it's captured by a sub, and it will only be visible to the subs that capture it.
For efficiency reasons, subs capture the fewest variables possible. If the sub doesn't reference $insertVar
, it won't capture it. Since your first testSub
doesn't reference $insertVar
, it doesn't capture it. Since $insertVar
has gone out of scope by the time you call testSub
, it's not available to eval
. You should get the warning Variable "$insertVar" is not available
, but for reasons unknown to me, it's issued for the specific code you used.
Your second testSub
reference $insertVar
, so testSub
captures $insertVar
and keeps it alive. Even though $insertVar
has gone out of scope by the time you call testSub
, it's available to eval
since it was captured by the sub.
If you declare the variables using our
, they'll be global package variables, and thus won't go out of scope, and they'll be available to eval
.
>perl -wE"use strict; use warnings; { my $x = 'abc'; sub foo { $x } } say foo()"
abc
>perl -wE"use strict; use warnings; { my $x = 'abc'; sub foo { eval '$x' } } say foo()"
Variable "$x" is not available at (eval 1) line 2.
Use of uninitialized value in say at -e line 1.
>perl -wE"use strict; use warnings; { our $x = 'abc'; sub foo { eval '$x' } } say foo()"
abc