5.3 Packages and Scope of Variables
5.3 Packages and Scope of Variables
A package is a namespace. A name such as a variable, function, or filehandle name belongs to a package. A package declaration affects only the so-called global names. Global names are those that are normally not explicitly declared before first use. In a file, a global name once used is available everywhere afterwards. An unassigned global variable has an undefined value. Variables declared with my are not considered global in Perl. They are statically scoped in that they are available within the current block—explicitly contained within braces, or an implicit block such as a whole file. When we have a variable declared with
my on top of a file, it is available everywhere in the file unless we my-redeclare a variable with the same name in the same or a contained block.
A package declaration affects the scope of a variable name, i.e., where the variable name can be seen and accessed. Let us look at the program given below.
Program 5.6
#!/usr/bin/perl #file global.pl $hometown = "Colorado Springs"; print "hometown = $hometown\n"; print "hometown again = $main::hometown\n"; package Tommy; print "Tommy's hometown = $hometown\n"; print "Tommy's hometown again = $main::hometown\n"; $state = "Colorado"; print "Tommy's state = $state\n"; package Sean; print "Sean's hometown = $hometown\n"; print "Sean's state = $state\n"; package main; print "Our hometown = $hometown\n"; print "Our state = $state\n";
There are three packages in this program file: main, Tommy and Sean. main is the package on top where no package name has been specified. main is the package in the bottom of the program where it is explicitly entered. $hometown as used on top is a global variable. As we know, only a global variable is affected by the package declaration. When we print
$hometown on the top of the program in the default main package right after the declaration, it is printed as expected. In the main package, we can qualify the variable name with the package name main if we want.
In the package Tommy, the global variable $hometown is not available without qualification since
$hometown is a name or identifier that resides in the main package. Similarly, $hometown is not available in the Sean package without qualification. It is available again at the bottom, with or without qualification in the package main. The $state variable is available without qualification only in package Tommy. The output of this program is given below.
hometown = Colorado Springs
hometown again = Colorado Springs
Tommy's hometown =
Tommy's hometown again = Colorado Springs
Tommy's state = Colorado
Sean's hometown =
Sean's state =
Our hometown = Colorado Springs
Our state =
The next program drives home the point.
Program 5.7
#!/usr/bin/perl #file global1.pl package Tommy; $hometown = "Colorado Springs"; print "Tommy's hometown = $hometown\n"; package Sean; print "Sean's hometown = $hometown\n"; package main; print "hometown = $hometown\n";
Here, the variable $hometown is global because it is an undeclared variable. It resides in the Tommy package and hence not available in any other package without qualification. The output of the program is given below.
Tommy's hometown = Colorado Springs Sean's hometown = hometown =
Variables declared with my are statically scoped. Such variables are not considered global. That is, their scope or availability within the program is determined by the block in which they are declared. In Perl, only a global variable is limited by a package declaration to belong to a certain namespace. A package declaration does not place any such restriction on my-declared variables. A variable declared with my cannot be qualified by a package name. The following program illustrates these scoping concepts.
Program 5.8
#!/usr/bin/perl #file my.pl use strict; my $hometown = "Colorado Springs"; print "hometown = $hometown\n"; print "hometown again = $main::hometown\n"; package Tommy; my $state = "Colorado"; print "Tommy's hometown = $hometown\n"; print "Tommy's state = $state\n"; print "Tommy's state again = $Tommy::state\n"; package Sean; print "Sean's hometown = $hometown\n"; print "Sean's state = $state\n"; package main; print "Our hometown = $hometown\n"; print "Our state = $state\n";
$hometown is declared with my on the top of the program. Hence, it is in the textual extent of the main package. However, it is not considered to belong to the main package. It is considered to be statically-scoped for availability in the complete textual extent of the file my.pl. Thus, there is a subtle distinction between what is considered global and what is statically-scoped. The two sets, as seen now, are disjoint. When we print $hometown, its value is printed, but when we print $main::hometown, Perl prints nothing since it does not print the value of the variable just assigned, but a global variable in the default package main. There is no such variable and therefore nothing is printed. A non-existent variable name qualified with a package name does not cause compilation error in Perl.
In package Tommy, a variable $state is declared with my and given a value. Since it is declared with my, it becomes statically available in the block where it is located. Here, there is only one implicit block, the whole file. Therefore, $state is available through the rest of the file. Since it is my-declared, its name cannot be pinned down to a specific package.
In package Sean, both variables printed get the values assigned earlier. The two variables have the values printed in the main package as well. The output of the program is given below.
hometown = Colorado Springs hometown again = Tommy's hometown = Colorado Springs Tommy's state = Colorado Tommy's state again = Sean's hometown = Colorado Springs Sean's state = Colorado Our hometown = Colorado Springs Our state = Colorado
In general, my-declared lexical variables are completely hidden from the outside world. That is, they are not seen from anywhere outside the block where they are declared, no matter what. In other words, they cannot be exported successfully.
Perl gives us a second way to declare a variable: our. The scope of a variable declared by our is exactly the same as that of a my-declared variable. That is, an our-declared variable is visible within the current block which may be the whole file. However, an our-declared variable becomes a global variable unlike a my-declared variable. Thus, an
our-declared variable is a global variable visible within the lexical scope of a block. Without our, only undeclared variables are global. Thus, our achieves what my and non-declaration achieve separately. Earlier we have seen that my-declared variables cannot be seen outside a block, and that my-declared variables cannot be qualified with a package name. We have also seen that an undeclared variable can be seen outside
its home package and can be qualified with a package. our-declared variables can also be seen outside the current block and can be qualified with a package name.
The following program is a modification of the immediately preceding program where the two my declarations have been changed to our.
Program 5.9
#!/usr/bin/perl #file our.pl use strict; our $hometown = "Colorado Springs"; print "hometown = $hometown\n"; print "hometown again = $main::hometown\n"; package Tommy; our $state = "Colorado"; print "Tommy's hometown = $hometown\n"; print "Tommy's state = $state\n"; print "Tommy's state again = $Tommy::state\n"; package Sean; print "Sean's hometown = $hometown\n"; print "Sean's state = $state\n"; package main; print "Our hometown = $hometown\n"; print "Our state = $state\n";
The output of the program is given below.
hometown = Colorado Springs hometown again = Colorado Springs Tommy's hometown = Colorado Springs Tommy's state = Colorado Tommy's state again = Colorado Sean's hometown = Colorado Springs Sean's state = Colorado Our hometown = Colorado Springs Our state = Colorado
We clearly see that an our-declared variable is
• available outside its home package without a package qualifier like an undeclared global variable, and
• can be qualified with a package name.
our makes a variable globally accessible in the current block. The current block may have several packages in terms of textual content. our does not make a variable globally accessible only inside the current package.
Now, we discuss a way to make a variable viewable globally inside a package. The package may be the only one in a file, or it may be one of several in a file. Of course, a real module may have many explicit blocks enclosed within braces. A package-global variable is accessible anywhere in the package unless a variable with the same name is declared elsewhere in the same package. A package-global variable is not available without qualification outside the home package. We make a variable package-global by declaring it with the pragma use vars. use vars takes a list of words and makes them globally available inside the current package. By global scope inside a package, we mean that the name is available inside all blocks that the package may contain. Also, if the package is available over several files (by using the package declaration), the name or identifier is available everywhere in the package. The following program illustrates the use of use vars.
Program 5.10
#!/usr/bin/perl #file usevar.pl use strict; use vars qw($hometown); $hometown = "Colorado Springs"; print "hometown = $hometown\n"; print "hometown again = $main::hometown\n"; package Tommy; use vars qw($state); $state = "Colorado"; print "Tommy's hometown = $main::hometown\n"; print "Tommy's state = $state\n"; print "Tommy's state again = $Tommy::state\n"; package Sean; print "Sean's hometown = $main::hometown\n"; print "Sean's state = $Tommy::state\n"; package main; print "Our hometown = $hometown\n"; print "Our state = $Tommy::state\n";
In this program, once again, we have the default package main, and two other packages Tommy and Sean. We start the program by declaring $hometown as a global variable within the confines of the implicit package main. use vars takes a list of quoted words. We can use qw to provide such a list if we want. Thus, $hometown can be seen in the package main only, without any qualification. It is not seen in any other package without the package name in front.
In the package Tommy, we declare $state as a package global variable. When we print $hometown declared in the package main in Tommy, it must be accessed as $main::hometown. Similarly, in the Sean package, both variables need to be qualified with the package name. The output of the program is given
below.
hometown = Colorado Springs hometown again = Colorado Springs Tommy's hometown = Colorado Springs Tommy's state = Colorado Tommy's state again = Colorado Sean's hometown = Colorado Springs Sean's state = Colorado Our hometown = Colorado Springs Our state = Colorado
