Here's what I found out about variable scopes:
my
declarations are pretty clear and straightforward if used inside blocks. If used in main outside any block, they are a bit different though, meaning that a my
variable declared outside a block is visible even inside functions called from anywhere inside the same file as long as these functions are defined within the same file. If declared inside a block, though, they are not visible to functions even if called from the same block. All my
variables seem to live on the stack. And: you cannot localize them with local
.
our
variables live on the heap. Even if you have a my
variable by the same name, the our variable can still be accessed through ${'var'}
, which looks up a variable of that name in the symbol table and dereferences it. my
variables, on the other hand, have not symbol table entries.
local
variables seem to me like a relic from former Perl versions. They are just re-assignments to global (our
) variables with block scope and resume their former values after the block terminates. I can see no real sense in using them.
My little program below shows all this, and it shows how badly a declared() test is missing, beyond the well-known defined() test, to identify undeclared variables as such.
#!/usr/bin/perl
use strict;
### This is about variable scoping with my, our and local
my $fsv = "file scope"; # visible for all code in this file
our $gsv = "global scope"; # not different from my $fsv, except in packages
our $lsv = "global"; # global scope, but localized in subsequent block
{
my $bsv = "lex scope"; # visible only inside this block, not even in subs called from here
$gsv = "visible everywhere";
local $lsv = "global, but localized val";
print "This is variable \$bsv with value $bsv inside block\n";
print "This is variable \$fsv with value $fsv inside block\n";
print "This is variable \$lsv with value $lsv inside block\n\n";
print_vars("calledfromblock");
}
print_vars("calledfromoutside");
no strict 'vars'; # needed if testing variable for declaredness rather than definedness
if ( defined $bsv ) {
print "\$bsv as defined outside braces: $bsv\n"
} else {
print "\$bsv not defined outside braces\n";
}
print "This is variable \$lsv with value $lsv outside block\n";
# use strict 'vars'; # no strict 'vars' effective even in sub print_vars unless switched back on
sub print_vars
{
my $whence = shift;
my $gsv = "my variable";
no strict 'refs'; # needed to access the global var $gsv using ${'gsv'} despite the my declaration
if ( $whence eq "calledfromblock" ) {
print "\t print_vars called from within the block:\n";
( defined $bsv ) ? print "\$bsv is $bsv inside sub\n" : print "\$bsv not defined inside sub\n";
( defined $fsv ) ? print "\$fsv is $fsv inside sub\n" : print "\$fsv not defined inside sub\n";
( defined ${'gsv'} ) ? print "\$gsv is ${'gsv'} inside sub\n" : print "\$gsv not defined inside sub\n";
( defined ${'lsv'} ) ? print "\$lsv is ${'lsv'} inside sub\n" : print "\$lsv not defined inside sub\n";
} else {
print "\t print_vars called from outside the block:\n";
( defined $bsv ) ? print "\$bsv is $bsv inside sub\n" : print "\$bsv not defined inside sub\n";
( defined $fsv ) ? print "\$fsv is $fsv inside sub\n" : print "\$fsv not defined inside sub\n";
( defined $gsv ) ? print "\$gsv is $gsv inside sub\n" : print "\$gsv not defined inside sub\n";
( defined $lsv ) ? print "\$lsv is $lsv inside sub\n" : print "\$lsv not defined inside sub\n";
}
print "\n";
}