5.5 Exporting Identifiers from a Module

5.5  Exporting Identifiers from a Module

   In this section, we discuss how variables and subroutines in a module can be made visible (or, invisible), and thus, usable (or, unusable) outside the module. In the modules we have seen in Sections 5.1, 5.2 and 5.6, all the variables are global, and hence visible from elsewhere. In other words, none of the variables in the packages or modules have been pre-declared. In these modules, all the variables are global, and hence visible from elsewhere when the names are fully qualified with the name of the package in front. In Section 5.3, we see how variable names can be made global inside a block, or global inside a package. In the example that follows in this section, we make all the
variables local to the file by declaring them with my. Variables declared with my have static scope in the block in which they occur. In this case, the block is the whole file. A file has only one package or module in it. Thus, these variables are invisible outside the module unless explicit mechanisms are made to make them visible. This ensures privacy and allows selective exporting of names. This holds for subroutine or method names as well.

We have a module called Sean.pm that is given below.

 Program 5.13

#!/usr/bin/perl
#file Sean.pm
use strict;

package Sean;
use Exporter;
use vars qw(@ISA @EXPORT);
@ISA = ('Exporter');
@EXPORT = qw($firstname  $hometown &height  &weight &age &year_met);
our($firstname); 
my ($hometown, $height, $weight, $age, $year_met);
$firstname = "Sean"; $hometown = "Montreal";
$height = 67; $weight = 140;
$age = 21; $year_met = 1995;

sub height{
    return $height;
}

sub weight{
   return $weight;
}

sub age{
   return $age;
}

sub year_met{
  return $year_met;
}

1;

The package declaration is right on top. As a result, the module goes into a new package where its variables and functions are stored. It uses a module called Exporter to be able to make selected identifiers available outside the module’s definition. Then, there is the following statement.

 

use vars qw(@ISA @EXPORT);     

 

This statement declares variables that are to be used only inside one package. Here, we declare variables that are global inside a package. Since the file contains only one package, they are global inside the file as well.

 

@ISA = ('Exporter');

 

This makes the current package Sean.pm inherit from the Exporter.pm module. Exporter.pm has a method called import that is inherited by Sean.pm. Thus, when in another program, one says

 

use Sean;

 

Perl calls the method

 

Sean->import()

 

that is inherited from Exporter.pm. This makes the exported variables, functions and methods available in the useing package.

The next statement assigns a value to @EXPORT. @ISA and @EXPORT are special Perl variables that are available inside each package. @EXPORT’s value specifies all variable, function and method names that are available outside. However, there is a catch that we see next.

The module has one variable $hometown declared with my. Variables declared with my are visible in the current file since the whole file is an implicit block. These variables’ values are not available outside the current file even if exported. The current file contains only one package and as a result, the variables declared with my are not seen outside the package and are thus, private to the package.

This is why Perl provides another way to declare statically scoped variables in addition to my. It is our. our declaration makes a variable scoped inside a block (which can be a file), but allows it to be exported when used in a situation where use strict is enforced. This is because our makes a variable global inside the block in addition to making it statically scoped inside the block. Note that we use & before names of exported functions to explicitly indicate that they are functions. The use of & is not necessary before a function name in Perl.

In the rest of the program, there are some assignment statements and function definitions. Next, we have a program that uses the package Sean.pm. This program is called friends1.pl.

 Program 5.14

#!/usr/bin/perl
#file friends1.pl
use strict;
use Sean;

print "Sean's firstname = ", $Sean::firstname, "\n";
print "Sean's hometown =  ", $Sean::hometown, "\n";
eval{print "Sean's hometown = ", Sean::hometown(), "\n";}
   or warn "$@";
eval{print "Sean's  height = ", height(), "\n";}
   or warn "$@";
print "Sean's weight = $Sean::weight\n";
eval{print "Sean's age = ", Sean::age(), "\n";}  
   or warn "$@"; 
eval{print "Year I met Sean =", Sean::year_met(), "\n";}
   or warn "$@";

The file uses the package Sean.pm. It simply prints the values of a few variables and makes a few function calls. We see that the value of $firstname is printed correctly because it is declared with our in Sean.pm. However, the value of $hometown is not exported correctly from Sean.pm to friends1.pl
in spite of the fact that $hometown is explicitly exported. That is because it is declared with my in Sean.pm and hence its value cannot be sent out even if its name is exported.

The other thing to note is that we make calls to the exported functions inside eval statements. This usage executes statements inside an eval. If there is an exception i.e., an error, eval catches it and makes it available in the variable $@. Without eval, any error is likely to cause the program to die. The output of the program is given below.

%friends1.pl
Sean's firstname = Sean
Sean's hometown =  
Undefined subroutine &Sean::hometown called at friends1.pl line 8.
Sean's  height = 67
Sean's weight = 
Sean's age = 21
Year I met Sean =1995

There is a way in which we can modify the Sean.pm so that variables can still be exported. It is by changing the our declaration to a declaration that uses use vars. We know that the use vars pragma makes the variables global inside the package. Let us change the Sean.pm to look like the following .

 Program 5.15

#!/usr/bin/perl
#file Sean.pm
use strict;

package Sean;
use Exporter;
use vars qw(@ISA @EXPORT);
@ISA = ('Exporter');
@EXPORT = qw($firstname  $hometown &height  &weight &age &year_met);
use vars qw($firstname $hometown);
my ($height, $weight, $age, $year_met);
$firstname = "Sean"; $hometown = "Montreal";
$height = 67; $weight = 140;
$age = 21; $year_met = 1995;

sub height{
    return $height;
}

sub weight{
   return $weight;
}

sub age{
   return $age;
}

sub year_met{
  return $year_met;
}

1;

If we now run the friends1.pl program given earlier, the output is the following.

Sean's firstname = Sean
Sean's hometown =  Montreal
Undefined subroutine &Sean::hometown called at friends1.pl line 8.
Sean's  height = 67
Sean's weight = 
Sean's age = 21
Year I met Sean =1995