In Perl 4 there was no modules and the shandard way to share the code was libraries, The Perl 4.036 standard library has 31 files. These files have been replaced in Perl 5.0 by a set of standard modules (see the following section). Libraries in Perl are similar to dot operation in shell and include the code into the namespace of the current package. The keyword require() is an amalog of dot operation in shell. The package mechanism by itself merely provides a way of segmenting the code into chunks. When this mechanism is is used to include a set of related subroutines stored in a single file we talk about library.
A library is effectively a collection of subroutines in a separate file. Setting up a file as a library file is a fairly straightforward process. Place the subroutines in a separate file, and add a package declaration to the top of the file. The file name of the library file and the package name should be the same. Then add the line
1;
to the end of the file (so that it returns TRUE when included by the require() function). If you want any of the subroutines to be in the global namespace automatically, change the name of the subroutine to explicitly name the main package (for example, main'mysub).
Package statement can be used to create a separate namespace. The following example illustrates how to declare a Perl 4.0 library with a single subroutine, filtest:
# Sample library file (Perl 4) package filtest; sub main::filtest { local($fil) = @_; -f $fil && print "File $fil is a normal file.\n"; -d _ && print "File $fil is a directory.\n"; } 1;
To use a library, you simply use require() to refer to the library name. Perl searches for all directories specified in the @INC special variable when it tries to locate this file. To include the sample library file specified in the preceding section, use the following code:
#!/usr/bin/perl -w # require "filtest"; filtest("/usr/bin"); filtest("/usr/etc/passwd");
Following are the files in the standard Perl 4.036 library, which have been
superseded by Perl 5.0 modules:
abbrev.pl | getcwd.pl |
assert.pl | getopt.pl |
bigfloat.pl | getopts.pl |
bigint.pl | importenv.pl |
bigrat.pl | look.pl |
cacheout.pl | newgetopt.pl |
chat2.pl | open2.pl |
complete.pl | perldb.pl |
ctime.pl | pwd.pl |
dumpvar.pl | shellwords.pl |
exceptions.pl | stat.pl |
fastcwd.pl | syslog.pl |
find.pl | termcap.pl |
finddepth.pl | timelocal.pl |
flush.pl | validate.pl |
require is like do , but it'll only do once. It'll record the fact that a file has been loaded and will ignore further requests to require it again. It also fails with an error if it can't find the file you're loading:
#!/usr/bin/perl # cantload.pl use warnings; use strict; require "nothere.pl"; will die with an error like this:
perl cantload.pl Can't locate nothere.pl in @INC (@INC contains: /usr/local/lib/perl5/5.6.0/cygwin /usr/local/lib/perl5/5.6.0 /usr/local/lib/perl5/site_perl/5.6.0/cygwin /usr/local/lib/perl5/site_perl/5.6.0 /usr/local/lib/perl5/site_perl .) at cantload.pl line 6. >This is the @INC array, which contains a list of paths where Perl looks for modules and other additional files. The first two paths are where Perl keeps the standard library. The first includes the word cygwin , which is the operating system I'm running on and contains the parts of the library specific to this operating system. The second is the part of the standard library, which does not depend on the operating system. In Windows, these two libraries are C:/Perl/lib and C:/Perl/site/lib by default. The next two paths are the local 'site' modules, which are third-party modules that we'll install from CPAN or create ourselves. The version number (5.6.0) reminds us that these are modules specific to that version. The next path doesn't have a Perl version number in it, and that's for site modules that do not need a particular version of Perl. Finally, the . represents the current directory. You can also use require like this: require Wibble; Using a bareword tells perl to look for a file called Wibble.pm in the @INC path. It also converts any instance of :: into a directory separator.
For instance, then: require Monty::Python; will send perl looking for Python.pm in a directory called Monty which is itself in one of the directories given in @INC .
Before Perl version 4, the only way to make a large scale Perl project, or scale up your code, was the ability to make functions and the ability to segregate variables into scopes. You could get pretty far with just these, but it limited Perl to 'one shot scripts'; scripts that were useful, but didn't have reusable components.
Perl4 came along, and added libraries or collections of functions that were related, which we shall address here. To make a library, you require it, just as you used modules.
The model for creating and using libraries in Perl is fairly simple:
sub rot13 {
my ($word) = @_;
$word =~ tr/A-Za-z/N-ZA-Mn-za-m/;
return($word);
}
sub piglatin{
my($word) = @_;
my (@letters) = split('', $word);
my ($first, $rest) = ($letters[0], join('', @letters[1..$#letters]));
return($rest . $first . "ay");
}
To actually use this library, put require "wordtrans.pl" at the
beginning of any script that wants to call piglatin, rot13, or anagram, for
example
require "recode.pl";will do a simple encryption of word by shifting each letter 13 'places' to the right ('A' becomes 'M', 'B' becomes 'N', etc). The keyword require is actually a call to the external script that executes the code inside that script. The main principle to remember is that when you require statement mean execution of the code in a particular library, for example:
my $curse = rot13('donnerweter');
print $curse;
if ($Config{'osname'} =~ m/nix/i){
This may sound simple enough. However, there is one issue that we haven't discussed yet: exactly how this mechanism works. Of course, I should also point out some of the small gotchas that can trouble new Perl programmers.
So, what happens when you say 'require "perlprog.pl"'? There are two things to remember here.
The main principle to remember is that when you write a library, and include it in a program, Perl simply executes the code in library.pl at the point which you say 'require library.pl'. For example, if you put the following statement inside the file library.pl:
print "Testing of require!n";
and then inside a program:
require "library.pl";
print "Done with require!\n";
Starting execution at line 1, Perl opens up, parses, and then executes the code inside library.pl. This prints out:
Testing of require!
Done with require!
The library code is not inserted in the main code until run time. When you say "require 'program.pl'", Perl executes that statement in exactly the place where it is called. Hence, the following:
{use Config;
if ($Config{'osname'} =~ m"nix"i)
require "UnixLibrary.pl";
} else {
require "NTLibrary.pl";
}
does exactly what you might expect, namely checking the operating system, and seeing if it is a variant of UNIX. If so, it requires the library UnixLibrary.pl. If otherwise, it assumes that you are using NT (we could make an explicit test here, too: Config would return 'MSWin32').
This principle can be abused quite readily to make very illegible code. (In fact, the above could be considered an abuse if used irresponsibly.) For example, you could say something like:
$library = "mylib";
require $library;
Since require is run-time, 'require $library' becomes 'require mylib'. Hence, here we dynamically decide, based on a variable, which library to include.
If you do this a lot, it will become almost impossible to sort through the way you structured your program. The less said about this the better, since the poor soul who has to maintain your code will be cursing your name as he searches through the layers of logic.
require is the older way to include code in Perl, therefore, there are a couple of caveats of which you should be aware. (use overcomes these caveats, so you are advised to learn it.) These caveats are listed below.
Since require does not enforce any type of convention for functions, there is always the chance that the names of functions will collide, or overlap, each other. For example:
lib1.pl:
sub get { print "lib1's version of get\n"; }
sub put { print "lib1's version of put\n"; }
lib2.pl:
sub get { print "lib2's version of get\n"; }
sub put { print "lib2's version of put\n"; }
Now what happens when you say something like:
require "lib1.pl";
require "lib2.pl";
get();
Well, the first thing Perl does is open up lib1.pl, and include the functions get and put. But then Perl goes on to open lib2.pl and include lib2's versions of the same functions. This means that when you say 'get()' in line 3, Perl prints out:
lib2's version of get
This is a name collision, which has caused Perl to ignore lib1 and run lib2's version instead. This error can cause a lot of debugging time in a ladge project.
Is this a mechnism that makes possible to aviod collitions. Yes, the best way to avoid this is by using namespaces as we will see below, so that your functions aren't in 'one big happy family' (i.e.: the main namespace), but in lots of smaller families. The flag '-w' will also show when namespaces collide. However, even then, on large, large projects you will get some name collision. In such cases you will benefit from the use of modules, and the keyword use instead.
This is a simple one, but you'd be surprised how many times this can catch you. Look at the following code:
if ($var1 !=1 ) { require "lib2.pl"; } else { require "lib1.pl"; }
in which lib1.pl and lib2.pl look like:
lib1.pl:
1 print "This has a Syntax Error!\n
lib2.pl:
1 print "This doesn't have a syntax error!\n";
Now, if $var1 is not equal to '1', then the program will
a) hit the statement 'require "lib2.pl"'
b) parse the code in lib2.pl
c) run correctly (and print out 'This doesn't have a syntax error').
In other words, it will do exactly what you expect, since lib2.pl contains valid Perl code.
However, if $var1 equals 1, then you will trigger the other part of the if clause, and things aren't so simple. What happens? Well, the same three things:
a) Perl will hit the statement 'require "lib1.pl"'
b) parse the code in 'require "lib1.pl"'
c) die with a syntax error. (since lib1.pl has a syntax error in it!)
This can be rather nasty, since the process that you run could have gone for hours before, and then and only then tell you that there is a problem in your code!
What to do about this? Well, the best thing to do is minimize your use of this form of require. In fact, I would go as far to say that you only use require this way in doing portable coding:
if ($UNIX) { require "UNIXLibrary.pl"; } else { require "NTLibrary.pl"; }
In fact, I would take the further precaution of wrapping this up in a use statement, since use statements include code before any of the code is actually run, that is, in the compile step. We shall talk about quite a bit later on, when we get to use.
In short, require lets you include code just as if the code was typed on the spot: 'require program.pl' opens up the Perl file 'program.pl', inserts it into the spot where require was called, checks it for syntax and then runs it. Hence, it can be useful in cases where you are not sure which library to call. However, in general, use is, well, more 'useful', as we shall see below.