Äîêóìåíòàöèÿ
HTML CSS PHP PERL äðóãîå

Scope

 
Previous Table of Contents Next

Scope

In the introduction for this hour, you learned that subroutines are used to take pieces of code and bundle them up and give them a name. You then can use this name to execute the code whenever you need it. You can also write the code within the subroutine so that it functions autonomously. That is, you can make it run and produce its return value using nothing but its arguments, the language's built-in functions and operators, and literal expressions within it. In that case, you can reuse the subroutine in other programs, because it no longer relies on the context it's being called in; it simply takes its arguments and data defined internally and produces a return value. The subroutine becomes a black box—stuff goes in, stuff comes out—and outside it you don't care what happens on the inside. Such a subroutine is called a pure function.

Now examine the following two snippets:


# One fairly good way to write this function

sub moonweight {

    ($weight) = @_;

    return($weight / 6);

}

print moonweight(150);



# A poor way to write this function.

sub moonweight {

    return( $weight/6 );

}

$weight = 150;

print moonweight;


In the long run, the first implementation shown here is a better one. It doesn't rely on any external variables—those outside the function—being set. It takes its argument, which it copies to $weight, and then does its calculations. The second implementation cannot easily be reused in another program; you would have to ensure that $weight is set properly and is not being used for some other value. If it were being used for something else, you would have to edit the moonweight() subroutine to use a different variable. That's not very efficient.

So, the first example is a better subroutine, but it's still missing something. The variable $weight could conflict with a variable named $weight somewhere else in the program.

Perl permits you to reuse variable names over and over and for different purposes within a large program. Perl's variables, by default, are visible in the main body of your program and in the subroutines; these kinds of variables are called global variables.

What you need to do in the moonweight example is to make the variable $weight a private variable in the subroutine. To do so, you use the my operator:


sub moonweight {

    my $weight;

    ($weight)=@_;

    return($weight/6);

}


Inside moonweight(), $weight is now private. Neither the main body nor any other subroutines in the program can access the value of $weight. Any other variables with the name $weight are completely separate from the moonweight() subroutine's $weight, so they are not affected by the assignment to $weight inside moonweight(). This subroutine is now completely self-contained.

The portion of the program in which the variable is visible is called the variable's scope.

You can use the my operator to declare scalar, array, and hash variables private to a subroutine. Filehandles, subroutines, and Perl's special variables—$!, $_, and @_, for example—cannot be marked as private to a subroutine. You can declare multiple variables private if you use parentheses with my:


my($larry, @curly, %moe);


Variables that are private to subroutines are stored in a completely different manner than global variables are. Global variables and private variables can have the same names, but they have nothing to do with each other, as shown here:


sub myfunc {

    my $x;

    $x=20;     # This is a private $x

    print "$x\n";

}

$x=10;         # This is a global $x

print "$x\n";

myfunc();

print "$x\n"; 


The preceding snippet prints 10, 20, and then 10. The $x inside the myfunc() subroutine is a completely different $x from the one outside. (Is it possible for a subroutine to use both its private $x and the global $x? Yes, but the answer is somewhat complicated and beyond this introductory book on Perl.)

Most of the time, Perl subroutines start by assigning @_ to a list of variable names and then declaring the list private to the subroutine:


sub player_stats {

    my($num_at_bats, $num_hits, $num_walks)=@_;

    # Rest of function...

}


This technique makes for a programmer-friendly subroutine: The variables are all private to the subroutine, so they cannot affect or be affected by other subroutines or the main body of the program. When a subroutine ends, any private variables are destroyed.

Other Places for my

You can also declare variables to have a scope that's even smaller than a subroutine. The my operator actually declares variables to be private to the enclosing block, which might or might not be a subroutine block. For example, in this snippet, the private variable $y (the one declared with my) is visible only within the block:


$y=20;

{

    my $y=500;

    print "The value of \$y is $y\n";   # Will print 500

}

print "$y\n";                           # Will print 20.


The declaration can even take place within one of the control structures, such as for, foreach, while, or if. Essentially, anywhere you have a block, a variable can be scoped so that it's visible only within that block, as in this example:


while($testval) {

    my $stuff;     # Visible only within the while() loop.

    :

}

foreach(@t) {

    my %hash;      # Visible only within the foreach loop.

}


In the preceding snippet, the my variables—$stuff and %hash—are created anew each time through the loops.

Perl versions 5.004 and newer allow the iterator in for and foreach loops and the test conditions in while and if structures to be declared as private to the block:


foreach my $element (@array) {

# $element is only visible in the foreach()

}



while(my $line=<STDIN>) {

    # $line is visible only in the while()

}


Again, when an enclosing block ends, any variables private to that block—and their values—are destroyed.

    Previous Table of Contents Next
    © 2000- NIV