Packages

The scope of a variable refers to that section of the program where a variable can be accessed. In a Perl program without any subroutines, all variables are global to the program. We've seen how a scope can be limited to a subroutine either dynamically, with local, or lexically through the use of my variables. Now we will look at the Perl package capability that allows for a further division of scope.

By default, a program has one package—the main package. You can create other packages by using the package statement. Packages provide a separate namespace so that you can avoid naming collisions. These collisions may happen if you are using libraries from two different sources and each source happens to choose the same name for a function or a variable. Below is a simple package contained in a file named Hotel.pl. See the folder HotelApp.


% type hotel.pl
#
#   Hotel.pl
#
package Hotel;
$name="The Perl Hotel";
sub reservation
{
        print "reservation at $name
";
}
sub cancellation
{
        print "cancellation at $name
";
}
1;
%

In Perl, there is the notion of a default package. When a Perl program begins, the default package is the main package. In order to use symbols from another package, you must use the :: operator to make qualified references. First, however, you must use require to load the new package. In one sense, packages are nothing more than named libraries. Here is an application that uses the Hotel.pl library. See the folder HotelApp.


% type hotelApp.pl
#
#   hotelApp.pl
#
require "Hotel.pl";
print $Hotel::name, "
";
Hotel::reservation();
Hotel::cancellation();
%

When the program begins, all references are assumed to be references to the default package, main. If you wish to make references to another package, you must qualify the reference with the :: operator.

print $Hotel::name, "
";
Hotel::reservation();
Hotel::cancellation();

You can always change the default package name with a package statement so that references can be made more easily.

print $Hotel::name, "
";
Hotel::reservation();
Hotel::cancellation();
package Hotel;          # Hotel is now the default package
print $name, "
";
reservation();
cancellation();

In the latter part of the above code, Hotel becomes the default package. Of course, this means that any names in the main package will now have to be qualified.

$message = "A simple message";
print "$message
";        # main in the default package
print $Hotel::name, "
";
Hotel::reservation();
Hotel::cancellation();
package Hotel;             # Hotel is the default package
print $name, "
";
reservation();
cancellation();
print "$main::message
";
package main;              # main is the default again
print "$message
";

Perl built-in variables such as $. and $_ always belong to the main package and thus never have to be referred to using the :: convention. my variables, on the other hand, are never part of a package, thus they can never be referenced using the :: notation.

Modules and Use

If a file contains a package, the package is usually fully contained in that file, but this is not a requirement. A file could consist of more than one package. Likewise, a package could be spread out over more than one file. However, neither arrangement is a common occurrence. The name of the file in which a package is defined is irrelevant in Perl 4. Most files that define packages in Perl 4 were conventionally named something.pl.

Beyond Perl 4, a more systematic approach is used. There is now a tight coupling between the file name and the package name. For example, if a package is named Math, then the file must be named Math.pm. In this approach only one package must be defined per file. Files that follow this approach are called Perl modules. Modules are imported into your program with the use statement.

The use statement loads only files whose names end in .pm—a Perl module, as described above. When you use use, you need to omit the .pm portion of the file you are loading.

use Math;
use English;
use Cwd;

There is also a technical difference between use and require. The former is executed during the first pass of the Perl interpreter, whereas the latter is executed during execution of the Perl program. Thus, the following will not work properly.

$name = "Math";
use $name;

Additionally, when use is used, the functions within the module are imported into the main package. Many Perl modules (.pm files) now ship with the Perl distribution. We will take a closer look at these modules later in Chapter 8. For now, we show how to use a few simple modules.

The module Cwd contains the function getcwd(), which returns the name of the current directory. In the program below, the system call chdir() is used a few times to change to a different directory. Each time there is a directory change, its name is printed by a call to getcwd(). See the folder Pwd.


% type pwd.pl
#
#   pwd.pl
#
use Cwd;
$cur = getcwd();            # get current directory name
print "Current directory is ($cur)
";
print "changing to $ARGV[0]
";
chdir ($ARGV[0]);           # change to directory $ARGV[0]
$pwd = getcwd();
print "Current directory is now ($pwd)
";
print "Changing to $cur
";
chdir ($cur);
print "Current directory is ($cur)
";
% perl pwd.pl ..
Current directory is (C:/OI/NetPerl/Chap05/Pwd)
changing to ..
Current directory is now (C:/OI/NetPerl/Chap05)
Changing to C:/OI/NetPerl/Chap05/Pwd
Current directory is (C:/OI/NetPerl/Chap05/Pwd)
%

Another handy module is the Benchmark module that is used to determine how long it takes to execute some code. For example, if you have two different algorithms to compute a factorial, you may want to know which one is faster. In the program below, one algorithm computes the factorial recursively and the other computes the factorial using iteration. See the folder Fact.


% type fact.pl
#
#   fact.pl
#
use Benchmark;
sub recur
{       my($item) = @_;
        return $item if ( $item == 1 );
        return $item * recur($item - 1);
}
sub iter
{       my ($item) = @_;
        my ($prod) = 1;
        while($item > 1)
        {
                $prod *= $item;
                $item--;
        }
        $prod;
}
timethese(500000, {    'iter'  => 'iter(10);',
                       'recur' => 'recur(10);'
                  }
);

The timethese function from the Benchmark module runs each function as many times as you specify (500,000 in the example above) and then produces the time it takes to run them.

% perl fact.pl
Benchmark: timing 500000 iterations of iter, recur...
iter: 10 wallclock secs ( 8.66 usr + 0.00 sys =  8.66 CPU)
recur: 23 wallclock secs (22.60 usr + 0.00 sys = 22.60 CPU)
%

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.202.54