Re: Variable scoping outside subs
by Roger (Parson) on Oct 27, 2003 at 23:44 UTC
|
Line 6 is never evaluated.
When you uncomment line 3, you get the following compilation (not run-time) error:
Global symbol "$var" requires explicit package name at p03.pl line 3.
Execution of p03.pl aborted due to compilation errors.
Because you have use strict; turned on, the Perl interpreter checks that a variable is created with my keyword before it is used, during the compilation stage.
If you move the line my $var = 1; to the end of the code (after sub test), you will get a compilation error.
Back to your original code with line 3 commented out, when the Perl compiler gets to the line my $var = 1;, it create an entry in the package's global symbolic/variable table for $var, with the value being undef. And when the compiler gets to sub test later, it checks to see if $var exists in the symbol table, and found it. So the compilation succeeds.
my $var = 1; has two components:
my $var; # compile time component inserts variable into scratchpad
# of the scope
$var = 1; # run-time component assigns the value
The value of the $var is set at run-time. Because line 6 is never executed, the initial value of $var is undef when you call the subroutine test.
use strict;
test();
#print "$var\n"; # Global symbol "$var" requires explicit...
exit;
my $var = 1;
sub test
{
print "var was undef\n" if $var eq undef;
print "var was '$var'\n";
$var++;
print "var is now '$var'\n";
}
And the output is -
var was undef
var was ''
var is now '1'
Updated: Thanks to welchavw for pointing out that the lexical variables are not stored in the package symbol tables. Instead, the lexical variables are stored in the scratchpad of the scope, file scope in this case.
| [reply] [d/l] [select] |
|
|
Roger,
I really like most of your explanation, which is much clearer than my attempt, but I am not sure that I agree completely. Lexicals are not inserted into any symbol table as far as I know, so I think that portion of the explanation may be erroneous.
,welchavw
| [reply] |
|
|
| [reply] [d/l] |
|
|
Excellent reply, thanks! ++
Minor nitpick... $var eq undef is the same as $var eq '':
perl -e'$var="";print "ooh" if $var eq undef'
- ><iper (who recently decided to log in...)
use japh; print;
| [reply] [d/l] [select] |
Re: Variable scoping outside subs
by welchavw (Pilgrim) on Oct 27, 2003 at 23:20 UTC
|
Neat failure, thanks for posting. Here's a try at an explain. That $var is compiled prior to test(), thus test() can refer to it (you can't move $var after test()), acting as a closure, as has been noted (++). However, as other posters have noted, line 6 does not get executed, so the assignment is never performed. The value of $var is undefined when printed, as a result.
Now, I actually rather believe that storage is allocated on-the-fly, during the call to test(), rather than at compilation-time.
Also, here's some additional test code I wroteup just to check some of my thoughts.
use strict;
&f; #"pre=> ", "post=>2"
my $v = 1;
&f; #pre=>1", "post=>3"
exit;
sub f {
print "pre=>$v\n";
$v += 2;
print "post=>$v\n";
}
update
Here's some further code that was illustrative to me.
#this code proves that scratchpads keep lexicals around,
#not mere copies of those lexicals; something like reference
#counting of lexicals is occuring with closures - the details
#don't really matter - the $v lexical persists in both the f1
#and f2 closures, not a mere "copy" of $v.
sub f_maker {
my $v = 1;
my $f1 = sub {
print "f1_pre =>$v\n";
$v++;
print "f1_post=>$v\n";
};
my $f2 = sub {
print "f2_pre =>$v\n";
$v++;
print "f2_post=>$v\n";
};
return ($f1, $f2);
}
my ($f1, $f2) = &f_maker;
&$f1;
&$f2;
&$f1;
__OUTPUT__
f1_pre =>1
f1_post=>2
f2_pre =>2
f2_post=>3
f1_pre =>3
f1_post=>4
| [reply] [d/l] [select] |
Re: Variable scoping outside subs
by Zaxo (Archbishop) on Oct 27, 2003 at 22:55 UTC
|
You exit before line 6 is reached - it is executed at runtime. You will get the behavior I think you expect by rearranging,
use strict;
{
my $var = 1;
sub test {
print "var was '$var'\n";
$var++;
print "var is now '$var'\n";
}
}
test();
exit 0;
The extra braces are just to limit the scope of $var further. Search closure here for much more.
the monastery: (36) | [reply] [d/l] |
Re: Variable scoping outside subs
by QM (Parson) on Oct 27, 2003 at 22:52 UTC
|
Line 6 is never evaluated. Execution ends at line 4.
If you want line 6 to execute before test is called, place it before the call to &test().
-QM
--
Quantum Mechanics: The dreams stuff is made of
| [reply] [d/l] |
|
|
You're missing my point, comment it out and see what happens.
| [reply] |
|
|
I agree the behavior is strange. It seems that Perl is processing the declaration at compile-time, which is why the variable exists when the sub is declared, but isn't processing the assignment until that line is reached in runtime, which never happens.
Perhaps you've touched on an area where the right thing to do is ambiguous, so Perl's idea of what to do differs from yours.
Several people have already shown you ways to make this work, by making sure the my statement precedes the call to test in both compile- and run-time.
| [reply] [d/l] [select] |
|
|
my has both compile-time and run-time effects. See Abigail's comment in Unusual Closure Behaviour, though that's not directly related to your problem. [and damn those spelling variations]
When the my line is commented out, I suspect that Perl is not complaining about the missing declaration because of the compile-time effect, even though the line is never executed.
-QM
--
Quantum Mechanics: The dreams stuff is made of
| [reply] [d/l] [select] |
|
|
| [reply] |
Re: Variable scoping outside subs
by leriksen (Curate) on Oct 29, 2003 at 00:26 UTC
|
| [reply] [d/l] |