Tib
Posted on May 11, 2021
Modules (and CPAN) are one of the "killer feature" of Perl, this article will discuss module loading/calling and some subtleties around this topic.
Where modules live do not dictate how they are called.
It is something important to understand early when you learn Perl programming, how you will load a module does not dictate its future package name (how it will be called).
Let's start with a simple example with a empty module stored in a File.pm
in a subdirectory:
Directory
└── Directory
└── File.pm
File.pm
contains nothing but a true
return value:
1;
The import is done by pointing to the path of the pm file:
#!/usr/bin/env perl
use Directory::Directory::File;
So far, all good! :D
But it is too simple, so let's continue with a more real world example that actually calls something:
package Directory::Directory::File;
sub foobar() {
print "Foo Bar!\n";
}
1;
It is imported and called like the following:
#!/usr/bin/env perl
# Import
use Directory::Directory::File;
# Call
Directory::Directory::File::foobar();
Notice that Directory::Directory::File::foobar();
matches the package declaration in the module file... Where actually when calling the modules functions/variables, we have to follow the package name decided by the author for its module (read the doc).
It could be Directory::Directory::File::foobar()
or something totally different from the path.
Look at this new example:
Directory
└── Directory
└── File.pm
The module is stored in Directory/Directory/File.pm
but belongs to package "Misleading" and declares/defines once again a function foobar
:
package Misleading;
sub foobar() {
print "Foo Bar!\n";
}
1;
On importer side, the use
and later the function call are not using the same "id" name:
#!/usr/bin/env perl
# Import
use Directory::Directory::File;
# But package is actually named "Misleading" !!!
Misleading::foobar();
# WON'T WORK!
# Directory::Directory::File::foobar();
N.B.: Please note that the good practice is to make match path and package name. But you can meet aliases
use vs require
The use
and require
are doing almost the same thing but at different phases.
The require documentation ends with "For a yet-more-powerful import facility, see use
and perlmod."
The use
keyword executes at compilation phase means before execution even if it's the last line of your program.
Here is my sample "Bazinga" module:
package Bazinga;
sub joke() {
print "Bazinga!\n";
}
1;
And trying to call the function joke
before to actually load it works very well:
$ perl -I. -e 'Bazinga::joke(); use Bazinga;'
Bazinga!
It would not be the same with imports at runtime.
$ perl -I. -e 'Bazinga::joke(); require Bazinga;'
Undefined subroutine &Bazinga::joke called at -e line 1.
With runtime imports, I can also import conditionally a module.
The following example will reload a module:
require Bazinga;
joke();
# Is it already loaded?
if ($INC{"Bazinga.pm"}) {
print "Press ENTER to reload module:";
<STDIN>;
delete $INC{"Bazinga.pm"}; # Remove it from list
require Bazinga; # Reload it
joke();
};
When you run this code, it will import and execute joke
then reload the module on "Enter" (and run joke
again).
Since it reloads the module, I can even change the module (the content of the joke
function) during the execution of the program:
sub joke() {
print "Knock Knock Knock Penny!\n";
print "Knock Knock Knock Penny!\n";
print "Knock Knock Knock Penny!\n";
}
1;
And everything becomes more dynamic:
Bazinga!
Press ENTER to reload module:
Knock Knock Knock Penny!
Knock Knock Knock Penny!
Knock Knock Knock Penny!
Perl module return value
Modules have to return a "true" value, it sometimes confuse beginners, but I read somewhere that it comes from Perl 4
where importing a module was much more like executing a subscript.
So what if we try to return a "false" value?
0;
When importing it, we get in trouble:
$ perl -I. -e 'use Boom;'
Boom.pm did not return a true value at -e line.
BEGIN failed--compilation aborted at -e line 1.
Why are there is 2 messages here?
There is one about importing and one about compilation because of the "phases" I mentioned just above.
Just replace use
per require
to change the phase where the import is processed and it will now only print the import failure:
$ perl -I. -e 'require Boom;'
Boom.pm did not return a true value at -e line 1.
Some people are playing with modules return codes like Michael G Schwern see his stackoverflow response or more recently PEVANS with a 0x55AA
in its Faster::Math
You can find more example of return values thanks to Acme::ReturnValue
-M
You can import a module with command line switch -M
like the following:
$ perl -I. -MBazinga -e 'joke()'
Bazinga!
Visibility
Namespace pollution and symbols export is an important topic that I will not discuss today but I leave you in a good company 😀
Posted on May 11, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.