I am seeing both of them used in this script I am trying to debug and the literature is just not clear. Can someone demystify this for me?
The short answer is that my
marks a variable as private in a lexical scope, and local
marks a variable as private in a dynamic scope.
It's easier to understand my
, since that creates a local variable in the usual sense. There is a new variable created and it's accessible only within the enclosing lexical block, which is usually marked by curly braces. There are some exceptions to the curly-brace rule, such as:
foreach my $x (@foo) { print "$x\n"; }
But that's just Perl doing what you mean. Normally you have something like this:
sub Foo {
my $x = shift;
print "$x\n";
}
In that case, $x
is private to the subroutine and its scope is enclosed by the curly braces. The thing to note, and this is the contrast to local
, is that the scope of a my
variable is defined with respect to your code as it is written in the file. It's a compile-time phenomenon.
To understand local
, you need to think in terms of the calling stack of your program as it is running. When a variable is local
, it is redefined from the point at which the local
statement executes for everything below that on the stack, until you return back up the stack to the caller of the block containing the local
.
This can be confusing at first, so consider the following example.
sub foo { print "$x\n"; }
sub bar { local $x; $x = 2; foo(); }
$x = 1;
foo(); # prints '1'
bar(); # prints '2' because $x was localed in bar
foo(); # prints '1' again because local from foo is no longer in effect
When foo
is called the first time, it sees the global value of $x
which is 1. When bar
is called and local $x
runs, that redefines the global $x
on the stack. Now when foo
is called from bar
, it sees the new value of 2 for $x
. So far that isn't very special, because the same thing would have happened without the call to local
. The magic is that when bar
returns we exit the dynamic scope created by local $x
and the previous global $x
comes back into scope. So for the final call of foo
, $x
is 1.
You will almost always want to use my
, since that gives you the local variable you're looking for. Once in a blue moon, local
is really handy to do cool things.