Leveraging Code with Modules

Modules can contain functions, data (or both) or object-oriented classes and there are a lot available from CPAN (the Comprehensive Perl Archive Network). They can be object-oriented or functional and it is generally better to use the object-oriented modules since these are easier to integrate with your code and are less likely to pollute your namespace.

Perl's Object Model

Perl doesn't really have an object-oriented model so this may seem like something that has been tacked onto a procedural language to allow it to use objects. It is!

In figure 155, we have the hello.pl script we have seen before.

		1.	#!/usr/bin/perl
		2.	# hello.pl by Bill Weinman <http://bw.org/contact/>
		3.	 
		4.	use 5.28.0;
		5.	use warnings;
		6.	 
		7.	say "Hello, World!";

Figure 155 - hello.pl

We will import a module into hello.pl by adding this line

use BW::Simple;

after line 5. This is similar to an include statement in C or Java. By default, Perl imports modules from the current directory, which in my case is a directory called Ch14, the full path name is not important here.

We can use tree to take a look at the directory structure here and the results are shown in figure 156.

		philip@raspberrypi:~/learning/perl/perl5EssentialTraining/Ch14 $ tree
		.
		├── BW
		│   ├── Better.pm
		│   └── Simple.pm
		├── carp.pl
		└── hello.pl

		1 directory, 4 files

Figure 156 - tree can be used to show the directory structure within the directory, Ch14

So, within the current directory, we have a directory called BW which contains our modules and inside it, there are two modules. Note that the module name has the extension, .pm, but we don't need to specify that within our Perl code.

It is normal practice, and it makes good sense, to group your modules into appropriate directories so you might, for example, have a directory for file reading which contains all of your modules related to that and another directory for actions which contain action-related modules and so on.

This is also helpful it helps to keep your namespace clean, the path is used for the namespace for the module.

Now, let’s take a look at the module we just imported.

		BW::Simple.pm
		1.	# Example perl module - by Bill Weinman <http://bw.org/contact/>
		2.	 
		3.	package BW::Simple;
		4.	use 5.28.0;
		5.	use warnings;
		6.	 
		7.	our $VERSION = "1.0";
		8.	 
		9.	sub new {
		10.	    my $inv = shift;
		11.	    my $class = ref($inv) || $inv;
		12.	 
		13.	    my $self = {};
		14.	    bless($self, $class);
		15.	 
		16.	    $self->{number} = shift || 0;
		17.	    return $self;
		18.	}
		19.	 
		20.	sub number {
		21.	    my $self = shift;
		22.	    return $self->{number} || 0;
		23.	}
		24.	 
		25.	sub string {
		26.	    my $self = shift;
		27.	    return "The number is: $self->{number}";
		28.	}
		29.	 
		30.	sub version {
		31.	    shift;
		32.	    return $VERSION;
		33.	}
		34.	 
		35.	1;

Figure 157 - the module, Simple.pm

Note that the module has a constructor called new. Calling the constructor is a convention rather than a requirement.

In this example, the constructor sets up a data structure that is used by the object and any objects built from the class. It uses the special function, bless, and this turns the structure into a class and we can then start initialising the data. It is convenient and very common to keep this data in a hash, although not required, and we have done that here. So, we have number that maps to either a string or a numeric variable depending on how the object is created.

Within the class, we have a 'class variable', which is actually just a global variable, $VERSION. Note that in spite of the fact that the name is all in upper-case, this is not a constant. This is a bit of a pollution of the name space, but it is conventional to do things this way in Perl.

We also have some getter methods and these are really just standard functions with one simple difference which we will come back to.

Going back to hello.pl, we can create an object with

my $o = BW::Simple->new(47);

So we are providing the number 47 which will be used to initialise the object (the constructor in Simple.pm uses shift to get this parameter).

We can call one of the methods like this

my $x = o->number;

This is simply using the getter method to return the value of number in the object and we are then assigning that to the variable $x. We can then output it. As a simple, we will amend the say statement in hello.pl to tag the number on to the end.

say "Hello, World! The number is $x";

Aside - Configuring Perl to Look for Modules in the Current Directory

When I tried to run hello.pl with the changes shown above, including importing the module Simple.pm, I got an error since the module was not found. This suggests that, in spite of the fact that the course video states that this is usually the default, it is not the case on my Raspberry Pi. This led me to do a little bit of research which led to the following.

How to Check Where Perl Looks for Modules

Perl looks for modules, typically, in a number of locations and these are stored in an array called @INC. We can check the contents of this array with the command

perl -V

This provides us with a lot of information about the version of Perl and the @INC array is at the end. There is some useful information about this on StackOverflow under the question, Does Perl look in the current directory (.) for modules? An interesting point, here, is that it seems that Perl will look in these directories before checking the pathname we provide. For example, the contents of @INC on my system were

		  @INC:
			PERL5LIB
			/etc/perl
			/usr/local/lib/arm-linux-gnueabihf/perl/5.28.1
			/usr/local/share/perl/5.28.1
			/usr/lib/arm-linux-gnueabihf/perl5/5.28
			/usr/share/perl5
			/usr/lib/arm-linux-gnueabihf/perl/5.28
			/usr/share/perl/5.28
			/usr/local/lib/site_perl
			/usr/lib/arm-linux-gnueabihf/perl-base

Figure 158 - the contents of the @INC array

You may notice that there is no reference to the current directory there. Now, if we have an import statement like

use BW::Simple;

this means that Perl will search through the paths listed in figure 158 and if the module is not found, it will search through the same paths with BW added at the end, so

		/etc/perl/BW
		/usr/local/lib/arm-linux-gnueabihf/perl/5.28.1/BW
		/usr/local/share/perl/5.28.1/BW

and so on.

Use Perl's -I Option to Provide an Additional Search Path

One option to get our code to run, although Perl does not know where to locate the module is to provide an additional search path at run time using the -I option (note that this is an upper-case i). So, for instance, we might run hello.pl with the following command

perl -I . hello.pl

In this case, we have specified the current directory as the additional path. This allows the code to execute, the module is imported and we see the expected output.

Adding a Directory to @INC

You can add a directory to @INC so that Perl will look in that directory for modules and this can be done on a session basis. However, if you want to make the change more permanent, you can add an export statement to your .bashrc file so that @INC is updated every time you log in. The easiest way to do that is with the command

echo "export PERL5LIB=.:PERL5LIB" >> $HOME/.bashrc

This makes the current directory the first place that Perl will look for modules. If you prefer to make it the last place that Perl looks, you can amend the command to

echo "export PERL5LIB=PERL5LIB:." >> $HOME/.bashrc

These methods as well as a lot of additional information are covered on the Perl page at WebFaction. This also covers topics such as installing modules from CPAN with cpanminus or cpanm and using perlbrew which allows you to experiment with different versions of Perl. They also provide all of this information in a very hand pdf document which can be downloaded via a link on the page.

It is also worth noting that having edited .bashrc, the change won't take effect until you restart the shell. In my case, since I am using kitty to ssh to a Raspberry Pi, I simply closed the session and started a new one. We can then use the same command to view the contents of @INC which now show as

		@INC:
			PERL5LIB
			.
			/etc/perl
			/usr/local/lib/arm-linux-gnueabihf/perl/5.28.1
			/usr/local/share/perl/5.28.1
			/usr/lib/arm-linux-gnueabihf/perl5/5.28
			/usr/share/perl5
			/usr/lib/arm-linux-gnueabihf/perl/5.28
			/usr/share/perl/5.28
			/usr/local/lib/site_perl
			/usr/lib/arm-linux-gnueabihf/perl-base

Figure 159 - the contents of the @INC array after adding the current directory

End of the Quick Aside!

So, we should now be able to run the script as normal and this gives the output

Hello, World! The number is 47

When we call a method on an object, the first object is always self, so this gives us a way of accessing the object data. Within this method (copied below for convenience)

		1.	sub number {
		2.	    my $self = shift;
		3.	    return $self->{number} || 0;
		4.	}

we use shift on line 2 to return the first argument (which is self). In essence, we are passing the object instance to the getter method and then using line 2 so that $self refers to the same instance. This means that we can then use $self within the method to access it's data so we can see that we are returning the value associated with number in that instance.

We can change the call to the method constructor to something like

my $o = BW::Simple->new("Forty seven");

This time, we have used a string to initialise the value in the object. When we use the getter method to return this value, we will be using the string version of this, so this will give us the appropriate output as follows

Hello, World! The number is Forty seven

One final point, Perl requires a module to end with a true value which is usually just a 1 (true value). You may have noticed this on the last line (line 35) of the module in figure 152.

1;

It looks like a type, but it is actually a requirement so you will most likely see it at the end of every Perl module.

An Example Module

If we look at the code in figure 160, this looks very much like the final version of the code from the previous example where we loaded in a module, created an object and called a method on that object.

		1.	#!/usr/bin/perl
		2.	# hello.pl by Bill Weinman <http://bw.org/contact/>
		3.	 
		4.	use 5.28.0;
		5.	use warnings;
		6.	use BW::Better;
		7.	 
		8.	my $o = BW::Better->new(47);
		9.	 
		10.	my$x = $o->number;
		11.	say "Hello, World! The number is $x";

Figure 160 - hello.pl with the addition of some code using the object model in Perl

The first thing to note is that rather than the Simple module, we are loading in a module called Better.pm and the code for this is shown in figure 161.

		1.	!# BW::Better.pm
		2.	# Example perl module - by Bill Weinman <http://bw.org/contact/>
		3.	 
		4.	package BW::Better;
		5.	use 5.28.0;
		6.	use warnings;
		7.	 
		8.	our $VERSION = "1.0";
		9.	 
		10.	sub new {
		11.	    my $inv = shift;
		12.	    my $class = ref($inv) || $inv;
		13.	 
		14.	    my $self = {};
		15.	    bless($self, $class);
		16.	 
		17.	    $self->{number} = shift || 0;
		18.	    return $self;
		19.	}
		20.	 
		21.	sub number {
		22.	    my $self = shift;
		23.	    $self->{number} = shift if @_;
		24.	    return $self->{number} || 0;
		25.	}
		26.	 
		27.	sub better {
		28.	    my $self = shift;
		29.	    $self->_make_better;
		30.	    return $self->{better} || 0;
		31.	}
		32.	 
		33.	sub string {
		34.	    my $self = shift;
		35.	    return "The number is: $self->{number}";
		36.	}
		37.	 
		38.	sub version {
		39.	    shift;
		40.	    return $VERSION;
		41.	}
		42.	 
		43.	sub _make_better {
		44.	    my $self = shift;
		45.	    my $num = $self->number() || 6;
		46.	    $num = 6 unless $num =~ /^[0-9]+$/;
		47.	    $self->{better} = $num + int(rand(10)) + 1;
		48.	}
		49.	 
		50.	1;

Figure 161 - the Better.pm module

We can run the version of hello.pl from figure 160, and we get the output

Hello, World! The number is 47

Just as we did previously, we can change the number that we use to create the object to a string and that will give us output like

Hello, World! The number is Forty seven

So, better works in exactly the same way as Simple, there is no difference to how we use it in our own code. The difference is in what happens behind the scenes.

Let's start with the constructor, which is called new. Within the constructor we create a variable called $inv (short for invocation) and set the value of this to the name of the class. We then create a variable called $class and initialise this with the name of the class which can be a string or a reference, depending on how the constructor is called.

This type of syntax is pretty much a standard in Perl.

On line 14, we set up a hash for our data and then we all bless with the data structure and the name of the class.

We then set the value of number to whatever argument was passed to new, in other words, that data we are using to create an object and we will set the value to 0 if no argument is supplied. We can see this in action if we change line 8 in hello.pl to

my $o = BW::Better->new();

Now, when we run the code, our output is

Hello, World! The number is 0

The constructor then returns $self which is actually the blessed object which is then assigned to the scalar variable, $o. This looks like a hash, from the perspective of the calling function. In fact, of we add the line

say $o

to hello.pl, this gives us the output

BW::Better=HASH(0x1039fb0)

So, the output displays the object (not the contents or the data of the object) and it identifies it as a hash. But it also has the name of the class and that is because it is blessed.

Another thing that is different in Better is that whereas we previously had a getter method for number (in Simple), we now also have a setter method. This means that we can modify the number from the hello.pl code (or any code that uses the module) with a statement such as

$x = $o->number(183);

and if we then output the number in the same way as we did before, we will see that the new value appears in the output

Hello, World! The number is 183

This works by taking the argument passed to the method using shift, if there is a number provided. If there isn't, it simply returns the current value. This means, we can also get the number with

$s = $o->number;

We also have a function (which we have seen in previous examples) called better which returns a 'better' number. That is, we add some random small value to the number to increase it slightly.

This method is called on an object and it gets that object, which has been passed to it from outside the module (from hello.pl, for example) and calls another method on that object. This other method, which is called make_better, is where we perform the operation that makes the number slightly larger and returns the increased value.

This is just showing that we can do a little more processing in the class and we can call methods. In our program, hello.pl, we can call this method with something like

say "A better number is " . $o->better;

If we tag this on to the end of hello.pl, it will give us output that looks something like

		BW::Better=HASH(0x4a6fb0)
		Hello, World! The number is 183
		A better number is 188

This type of syntax is going to look strange if you are used to other object-oriented languages such as Java or C++. However, it is fairly simple and easy to use and it makes it possible for us to program with objects in Perl.

Using Carp for Error Messages

Carp is a flexible error reporting module which is, by default, installed with Perl. In figure 162, we have a script called carp.pl which demonstrates

		1.	#!/usr/bin/perl
		2.	# carp.pl by Bill Weinman <http://bw.org/contact/>
		3.	 
		4.	use 5.28.0;
		5.	use warnings;
		6.	use Carp;
		7.	 
		8.	func();
		9.	say "returned from function.";
		10.	 
		11.	sub func {
		12.	    die "This is an error message,";
		13.	}

Figure 162 - carp.pl which demonstrates a simple form of error reporting using the dir function

This is a very simple script, and it makes use of the die function that we saw previously. To recap, on line 8, we call the function, func, and this simply executes the die function with an error message and it gives us the output

		This is an error message, at carp.pl line 12.  
	

So this is a hard error which terminates execution. We have another line of code on line 9, after the function call, but this is not executed.

Note that on line 5, we have specified

use carp;

so as an alternative to die, we can use the carp function on line 12.

carp "This is an error message,";

Now, if we run the code, we get the output

		This is an error message. at carp.pl line 12.
				main::func() called at carp.pl line 8
		returned from function.

A couple of things that are notable here are that the error message is more rich and we have a little stack trace. In addition, unlike the die function, the carp function did not terminate execution and so the statement on line 9 is executed.

If we do want the code to terminate execution, carp also provides a function called croak. If we change line 12 to

croak "This is an error message,";

when we run it, we get the output

		This is an error message. at carp.pl line 12.
				main::func() called at carp.pl line 8

So, we are seeing the same richer error message and stack trace we saw with carp, but the program execution does terminate.

There is also a function included with carp and it is called confess. It is similar to croak and I believe it provides more information in some circumstances. However, you won't always see a difference so it may be hard to tell exactly how it differs from croak.

The following excerpt is from the Perl Cookbook which is hosted online by the Institute of Technology.

"If the function is part of a module, consider using the Carp module and call croak or confess instead of die. The only difference between die and croak is that with croak, the error appears to be from the caller's perspective, not the module's. The confess function, on the other hand, creates a full stack backtrace of who called whom and with what arguments."

So there are a number of options and you will usually find that croak and carp are the most common. The documentation for carp can be found here.