Полезная информация

Advanced Perl Programming

Advanced Perl ProgrammingSearch this book
Previous: 6.4 PrivacyChapter 6
Next: 6.6 Nesting Packages

6.5 Importing Symbols

Sometimes, you may want to selectively import symbols into your namespace, just for typing efficiency. For example, you might want to say sqrt instead of math::sqrt or deposit instead of BankAccount::deposit. The use statement allows you to specify an optional list of function names to be imported:

use BankAccount ('withdraw', 'deposit');
withdraw();  # Can now call function without fully qualifying it.

For its part, the module has to be ready to export these names (and only them) to whoever uses it. It should also have a policy for what it should do if the user does not specify a list at all. Both these tasks are handled for you by a standard module called Exporter. The BankAccount class can be implemented as shown next:

package BankAccount;
use Exporter;
@ISA = ('Exporter');     # Inherit from Exporter
@EXPORT_OK = ('withdraw', 'deposit');

sub deposit  { .... }
sub withdraw { .... }

This code loads the Exporter module and arranges to inherit from that module, using the @ISA array. For now, take it on faith that this works; we will study inheritance shortly. The @EXPORT_OK array states which symbols are fine to export. The user of this module can in turn specify a list of one or more symbols specified in @EXPORT_OK to the use statement. If the user says,

use BankAccount ('deposit');

the deposit function can be called without fully qualifying the name, in contrast to withdraw(). To tell the Exporter module not to export any symbols into your namespace, leave the list blank.

If the module uses @EXPORT instead of @EXPORT_OK, the user gets all the exported symbols, regardless of whether they were mentioned in the import list or not. I recommend that as a module writer, you use the more polite @EXPORT_OK .

Please see the Exporter documentation for numerous other features, which, among other things, allow the user of the module to import groups of functions using tag names, or to specify the group using one or more regular expressions.

6.5.1 How Do use and Exporter Work?

If you are not interested in the details of how use and Exporter work, you can easily skip this section without loss of continuity. This is one of those "knowledge for knowledge's sake" kind of sections.

The statement

use BankAccount ('withdraw', 'deposit');

behaves exactly as if you had said

BEGIN { require BankAccount; 
        BankAccount::import('withdraw', 'deposit');}

BEGIN ensures that this statement is parsed and executed as soon as it is seen. require loads the file BankAccount.pm if it has not been loaded already. Finally, the import subroutine is called on that module.[3]

[3] A bit of a white lie here. It actually does BankAccount->import (uses an arrow instead of the ::), a slightly different way of calling a subroutine. We'll study this notation in detail in Chapter 7, Object-Oriented Programming. For now, this explanation is adequate.

import is not a Perl keyword. It is simply a call to a user-defined subroutine known as import, and the module can define it any way it wishes and do what it wants with its argument list. If BankAccount does not define import and doesn't inherit it, there is no difference between use BankAccount and require BankAccount. By using Exporter, a module can simply inherit an import method without having to implement it.

To understand how Exporter works, let us build an import subroutine ourselves. We develop a simple module called Environment that lets us quickly access environment variables. This is how we want to use it:

use Environment;
print $USER, $PATH;

Instead of saying $ENV{'USER'}, we can now simply say $USER. In other words, the Environment module (and specifically a function called import in that module) installs variables like $USER and $PATH in its caller's namespace.

Example 6.1 shows one way to do write this subroutine.

Example 6.1: Environment.pm: Create Variables Corresponding to Environment Variables

package Environment;
sub import {
    # Get some caller details; its package name, and the current file name
    # and line number
    my ($caller_package) = caller; 
    foreach $envt_var_name (keys %ENV) {
         *{"${caller_package}::${envt_var_name}"} = \$ENV{$envt_var_name};
1;  # To signify successful initialization

To keep the example small, import ignores its parameter list. It uses the caller built-in function to find out the calling package's name and creates aliases in that package. For an environment variable USER, the statement inside the foreach line is translated to this:

*{"main::USER"} = \$ENV{USER};

assuming that main is the calling package.

This small nugget encapsulates most of the knowledge of Chapter 3. The right-hand side returns a reference to the scalar containing the value of the environment variable, which is assigned to a typeglob. (Remember our discussion of selective aliasing?) The typeglob expression on the left creates a symbol table entry in main's symbol table, whose scalar component is made to point to the value from the right-hand side. Exporter works exactly the same way, except that it aliases only function names.

Incidentally, the standard Perl distribution contains a module called Env that looks quite similar to our Environment package. The only distinction is that instead of creating an alias of the environment variables, Env uses the tie mechanism,[4] a much more inefficient way of doing things than the approach just shown.

[4] We'll discuss the tie approach in Chapter 9, Tie.

Previous: 6.4 PrivacyAdvanced Perl ProgrammingNext: 6.6 Nesting Packages
6.4 PrivacyBook Index6.6 Nesting Packages