Using Local Variables in Subroutines

Structuring a Perl script to use subroutines that refer to the same global variables as the code outside the subroutines is essentially an exercise in code formatting. The subroutines in this case don't give you much intrinsic value in terms of efficiency or effective script design. Subroutines are much better designed and used as self-contained units that have their own variables and that deal only with data passed to that subroutine through arguments and passed back through return values. This makes them easier to manage, easier to reuse, and easier to debug. We'll work towards that goal as this lesson progresses, but we'll start here with a discussion of local variables.

The vast majority of the variables we've been looking at up to this point—scalar, list, and array variables—have been global variables, that is, they're available to all parts of the script, and continue to exist as long as the script runs. We've seen a few minor exceptions—the element variable in a foreach loop or the match variables in regular expressions, for example—but for the most part we've been looking solely at variables as having global scope.

Local variables, in the context of a subroutine, are variables that spring into existence when the subroutine is called, are available solely to that subroutine, and then disappear when the subroutine is finished. Other than the fact that they're local, they look just like other variables and contain the same sort of data.

Perl actually has two different ways of creating two different kinds of local variables. We'll cover one way (the easiest one) here, and deal with the other and the specific differences between the two on Day 13, “Scope, Modules, and Importing Code.”

To create a local variable for a subroutine, use the my modifier before you initialize or use the variable for the first time:

my $x = 1;  # $x is now local

The my modifier only applies to a single variable. If you want to create multiple local variables you have to enclose them in parentheses, like this:

my ($a, $b, $c);   # three locals, all undefined.

In the previous section we created a subroutine that prompted for two numbers and summed them. In that example the two number variables, $num1 and $num2 were global variables. We can make a single-line change to make those variables local variables:

$sum = &sumnums();
print "Result: $sum
";

sub sumnums {
   my ($num1, $num2);
   print 'Enter a number: ';
   chomp($num1 = <STDIN>);
   print 'Enter another number: ';
   chomp($num2 = <STDIN>);
   return $num1 + $num2;
}

In this version, the line my ($num1, $num2) creates variables that are local to the subroutine. They are available to the subroutine as temporary placeholders for the numbers, but are not visible outside the boundaries of that subroutine.

What happens if you create a my variable that has the same name as a previously used global variable? Perl has no problem with this; the new variables created by my will hide the global variables with the same name. Then, when the subroutine is done, the my variables will go away and the global variables will be visible (and usable) again. Because this can often be very confusing to debug, it's generally a good idea to give your local variables different names from global variables, or to simply avoid the use of global variables altogether.

Note

You can get to the values of global variables from inside a subroutine that declares my variables of the same name by putting your code into a package, and then referring to the package name and the global variable name. But I won't discuss that here; see Day 13 for details.


Here's an example that demonstrates how this works:

#!/usr/ bin/perl -w

$value = 0;
print "before callsub, $value is $value
";
&callsub();
print "after callsub, $value is $value
";

sub callsub {
    my ($value);
    $value++;
    print "inside callsub, $value is $value
";
}

If you run this example, you'll get the following output:

before callsub, $value is 0
inside callsub, $value is 1
after callsub, $value is 0

Note here that the my variable $value is a new variable, local to the subroutine. Changing its value has no effect on the global variable once the subroutine is complete.

The one other catch to watch out for with my variables is that they are truly local to the subroutine definition itself. If you nest subroutine calls—call one subroutine from another subroutine—the my variables defined in the first subroutine will not be available to the second subroutine, and vice versa. This is different from many other languages, where local variables cascade to nested subroutines. With my variables, you can only use them inside the same subroutine definition and nowhere else in the script.

Note

For the computer scientists in the audience, this means that my variables have lexical scope, rather than dynamic scope. They only exist inside the lexical block in which they are defined. There is more about this later in the book when we get to scope.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset