HTML CSS PHP PERL

5.1 Package Variables vs. Lexical Variables

 
Previous Table of Contents Next

5.1 Package Variables vs. Lexical Variables

First I must take a diversion to explain something that will be referred to heavily in the rest of this chapter. Perl enjoys a unique status among languages by having two types of variables: package variables and lexical variables. You can actually refer to, say, $x, in two places in your program and be referencing two different variables that were both in existence at the same time. Many people are blissfully ignorant of this fact because they either program in the old Perl 4 style (Perl 4 had only package variables, not lexical variables), or they always use my to declare variables (thereby creating only lexical variables). And if you're following good program development practice, which means enabling the strict pragma and declaring all variables with my, you might create Perl programs of your own for years up to level 4, say, without ever being aware of these two variable families. But for maintaining inherited programs, you have to learn about them.

Lexical variables were new in Perl 5, but they are much safer to use because unlike package variables, they are not globally visible; therefore they became the variables of choice for the discerning Perl programmer. You need a good reason to use a package variable these days, although there are some times you have no choice.

Lexical variables are declared with my. If you inherit a program containing a variable that isn't declared with my, that is a package variable and is visible from any part of the program, even other files, and even other packages (as long as they know what package the variable is in). They can just reach right in and do whatever they want with it. Like all strong magic, this can be used for good . . . or evil. For instance, the File::Find module allows you to change its behavior by setting package variables, such as $File::Find::dont_use_nlink if you're using AFS. This is a succinct interface, as is using the variable $File::Find::name to get at the full path to the current file:


# Print full paths for symbolic links

use File::Find;

$File::Find::dont_use_nlink = 1;  # For AFS

find(sub { print "$File::Find::name\n" if -l }, '.');

But a program that has gone over to the dark side may set and read package variables from all kinds of unexpected places, making it incredibly difficult to tell how it works. Programmers call this kind of gross violation of encapsulation action at a distance. Use lexical variables as much as possible and you're less likely to make that mistake.

5.1.1 Your Friendly local Perl Function

Some variables can't be declared with my; these are variables that belong to Perl, so you can't go getting possessive over them. An example is the special array @ARGV (which is initialized with the command-line arguments). Sometimes, it's convenient to temporarily reassign to that array. Suppose you want to read information from several configuration files. Perl's "diamond" operator <> makes this easy; it reads lines in succession from all the files named in @ARGV, opening and closing the files behind the scenes for you. So we can appropriate the diamond operator for our use even when the files we want to open aren't listed on the command line, by just setting @ARGV first.

Suppose, however, we want to get at the original command-line arguments after this phase. We can't declare a new @ARGV with my; it doesn't belong to us, because it's special. No problem; we just override @ARGV like this:


{

  local @ARGV = @CONFIG_FILES;

  while (<>)

  {

    # Do something with $_

  }

}

The local function hides the previous version of @ARGV in a location that will be restored on exit from the current scope. The new version it creates is initialized with a copy of the array @CONFIG_FILES, which our program earlier set to the list of configuration file names. We can then use the diamond operator to read those files, safe in the knowledge that when we exit the outer block, the original copy of @ARGV is restored to its rightful place. "Naked blocks" like the outer block in this example are frequently useful for creating a temporary scope.

You can find other variables that don't belong to you listed in the perlvar documentation page. However, there are some other variablespackage variablesthat Perl also puts to special use. For instance, if you call a subroutine that doesn't exist, but have defined a subroutine in that package called AUTOLOAD, Perl calls that subroutine instead. This feature is handy when you don't want to define subroutines at compilation time, but you would like to know what subroutine the user was attempting to call; so Perl sets the $AUTOLOAD package variable to the name of that subroutine:


# Let's say we're in package 'MyPack'

sub AUTOLOAD

{

  my $method = $MyPack::AUTOLOAD;  # Copy to private variable

  $method =~ s/.*://;              # Strip off package

  # Now the name of the subroutine being called is in $method

}

Other package variables that are also useful to Perl include: $VERSION (version number of current package), @ISA (classes we inherit from), and @EXPORT and similar variables used by the Exporter module.

5.1.2 With a Little Help from our Friends

Perl 5.6.0 introduced the our function, which makes life easier when you want to work with package variables. It is equivalent to use vars in that it allows you to refer to variables in the current package without fully qualifying them, but unlike use vars, it is lexically scoped, so its variable names aren't valid in your program long after you were done with them. (Yes, it is a little weird to speak of a declaration of package variables being lexically scoped. Just remember that the "lexical" part refers to the scope over which you can refer to the variable by its unqualified name, even though the value of that variable is globally visible.) use vars, on the other hand, is file scoped.

Take for example our earlier AUTOLOAD function. It was a nuisance to have to hard-code our package name in there (not that we couldn't have gotten around it with __PACKAGE__ and a symbolic reference, mind). With our, we don't need to:


sub AUTOLOAD

{

  our $AUTOLOAD;           # Now I can just say $AUTOLOAD

  my $method = $AUTOLOAD;  # Copy to private variable

  $method =~ s/.*://;      # Strip off package

  # Now the name of the subroutine being called is in $method

}

5.1.3 Lexical vs. Dynamic Scoping

Why are variables declared with my called lexical variables? Because that describes their scope. If you open a Perl program in an editor, start selecting text from the statement following a my declaration, and highlight code until the end of the enclosing block (or the end of file, if that comes first), everything you've highlighted is the scope of the variable in the declaration. Subroutines called from within that highlighted text won't see the variable unless they are also highlighted.


while (<SOMEFILEHANDLE>)

{

  my @words = split;

  # @words can be seen until the end of this block

}

# Now @words can no longer be used as a variable name

# (except by declaring a new variable with that name)

Package variables (and most of Perl's special variables listed in perlvar) can be saved temporarily with local. On the other hand, lexical variables can't be localized, but don't need to be; if you want to temporarily override a lexical variable just declare it again with my in an inner scope. Declaring a lexical variable twice at the same scope level triggers a warning.

Dynamic scoping derives its name from the fact that it is determined at run time. A package variable can always be referred to, even if nothing has ever set it, just like you can refer to a member of a hash even if it hasn't been set, and get undef back.[1] So in terms of where you can use its name, a package variable has global scope.

[1] It's even more like that than it seems; package variables are accessed via special hashes.

As to the lifetime of the value of that package variable, if you assign a temporary value with local, that value is seen by all code that runs until Perl exits the block containing the local, at which point it returns to its previous value. By way of example:


1  $main::global = "outer";

2  {

3    my $lexical = "private";

4    check_vars();

5    local $main::global = "inner";

6    check_vars();

7  }

8  check_vars();

9

10 sub check_vars

11 {

12   print $main::global;

13 }

At line 1 I assign a value to the package variable $main::global. (Because I use strict, it forces me to refer to the variable with its full name like that. More on use strict later.) The block that follows defines a lexical variable $lexical. If any code referred to that variable, it would have to be on lines 4, 5, or 6. Even though check_vars() is called from the same block, the code for check_vars() isn't in that block, and so that subroutine can't refer to $lexical. If I want that subroutine to see $lexical, I'll have to pass it in the argument list.

But $main::global is a different story. The check_vars() on line 4 will see a value of "outer" for that package variable. The check_vars() on line 6 will see a value of "inner." The check_vars() on line 8 will see a value of "outer" because the block in which the variable was localized has ended. See [DOMINUS98] for more about scoping.

    Previous Table of Contents Next
    © 2000- NIV