home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Perl CookbookPerl CookbookSearch this book

10.13. Saving Global Values

10.13.3. Discussion

Despite its name, Perl's local operator does not create a local variable. That's what my does. Instead, local merely preserves an existing value for the duration of its enclosing block. Hindsight shows that if local had been called save_value instead, much confusion could have been avoided.

Three places where you must use local instead of my are:

  1. You need to give a global variable a temporary value, especially $_.

  2. You need to create a local file or directory handle or a local function.

  3. You want to temporarily change just one element of an array or hash.

10.13.3.1. Using local( ) for temporary values for globals

The first situation is more apt to happen with predefined, built-in variables than with user variables. Often these are variables that Perl consults for hints for its high-level operations. In particular, any function that uses $_, implicitly or explicitly, should certainly have a local $_. This is annoyingly easy to forget to do. See Recipe 13.15 for one solution to this.

Another common target for local is the $/ variable, a global that implicitly affects the behavior of the readline operator used in <FH> operations.

$para = get_paragraph(*FH);        # pass filehandle glob 
$para = get_paragraph(*FH);        # pass filehandle by glob reference
$para = get_paragraph(*IO{FH});    # pass filehandle by IO reference
sub get_paragraph {
    my $fh = shift;  
    local $/ = '';        
    my $paragraph = <$fh>;
    chomp($paragraph);
    return $paragraph;
}

10.13.3.3. Using local( ) on parts of aggregates

The third situation is exceedingly rare, except for one common case. Because the local operator is really a "save value" operator, you can use it to save off just one element of an array or hash, even if that array or hash is itself a lexical!

my @nums = (0 .. 5);
sub first { 
    local $nums[3] = 3.14159;
    second( );
}
sub second {
    print "@nums\n";
} 
second( );
0 1 2 3 4 5
first( );
0 1 2 3.14159 4 5

The only common use for this kind of thing is for temporary signal handlers.

sub first {
    local $SIG{INT} = 'IGNORE';
    second( );
}

Now while second is running, interrupt signals are ignored. When first returns, the previous value of $SIG{INT} is automatically restored.

Although a lot of old code uses local, it's definitely something to steer clear of when it can be avoided. Because local still manipulates the values of global variables, not local variables, you'll run afoul of use strict unless you declared the globals using our or the older use vars.

The local operator produces dynamic scoping or runtime scoping. This is in contrast with the other kind of scoping Perl supports, which is much more easily understood. That's the kind of scoping that my provides, known as lexical scoping, or sometimes as static or compile-time scoping.

With dynamic scoping, a variable is accessible if it's found in the current scope—or in the scope of any frames (blocks) in its entire subroutine call stack, as determined at runtime. Any functions called have full access to dynamic variables, because they're still globals, just ones with temporary values. Only lexical variables are safe from such tampering.

Old code that says:

sub func {
    local($x, $y) = @_;
    #....
}

can almost always be replaced without ill effect by the following:

sub func {
    my($x, $y) = @_;
    #....
}

The only case where code can't be so upgraded is when it relies on dynamic scoping. That would happen if one function called another, and the latter relied upon access to the former's temporary versions of the global variables $x and $y. Code that handles global variables and expects strange action at a distance instead of using proper parameters is fragile at best. Good programmers avoid this kind of thing like the plague. (The solution is to explicitly pass values as parameters, rather than storing them in shared global variables.)

If you come across old code that uses:

&func(*Global_Array);
sub func {
    local(*aliased_array) = shift;
    for (@aliased_array) { .... }
}

this should probably be changed into something like this:

func(\@Global_Array);
sub func {
    my $array_ref  = shift;
    for (@$array_ref) { .... }
}

They're using the old pass-the-typeglob strategy devised before Perl supported proper references. It's not a pretty thing.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.