JavaScript EditorFreeware JavaScript Editor     Perl Tutorials 



Main Page Previous Section Next Section

Recipe 10.13 Saving Global Values

10.13.1 Problem

You need to temporarily save away the value of a global variable.

10.13.2 Solution

Use the local operator to save a previous global value, automatically restoring it when the current block exits:

our $age = 18;          # declare and set global variable
if (CONDITION) {
    local $age = 23;
    func( );         # sees temporary value of 23
} # Perl restores the old value at block exit

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.2 Using local( ) for local handles

The second situation used to arise whenever you needed a local filehandle or directory handle—or more rarely, a local function.

$contents = get_motd( );
sub get_motd {
    local *MOTD;
    open(MOTD, "/etc/motd")        or die "can't open motd: $!";
    local $/ = undef;  # slurp full file;
    local $_ = <MOTD>;
    close (MOTD);
    return $_;
}

If you wanted to return the open filehandle, you'd use:

return *MOTD;

However, in modern releases of Perl, you would make use of the filehandle autovivification property:

$contents = get_motd( );
sub get_motd {
    my $motd;  # this will be filled in by the next line
    open($motd, "/etc/motd")        or die "can't open motd: $!";
    local $/ = undef;  # slurp full file;
    return scalar <$motd>;
}

When the function returns, the anonymous filehandle is automatically closed for you. However, if you'd chosen to return $motd, then it wouldn't be. This is explained more fully in the Introduction to Chapter 7.

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.

10.13.4 See Also

The local, my, and our functions in Chapter 29 of Programming Perl and perlfunc(1); Chapter 6 of Programming Perl; the section on "Scoped Declarations" in Chapter 4 of Programming Perl; the sections on "Private Variables via my( )" and "Temporary Values via local( )" in perlsub(1); Recipe 10.2; Recipe 10.16

    Main Page Previous Section Next Section
    


    JavaScript EditorJavaScript Verifier     Perl Tutorials


    ©