1. Introduction

The two previous lectures supplied you with enough knowledge to know how to program most perl scripts. That is, with some help from the perl man pages, especially the perlfunc one.

If however, you wish to maintain a more complex perl program, you will probably outgrow the functionality that was covered so far. However, perl has certain mechanisms that make it to easier to write code that is more scalable, more modular and more re-usable.

The purpose of a modular code is to make sure there isn't any duplicate code, and that parts of the code can later be used by others, with as little modification as possible. Perl, as most other languages, does not force writing modular code upon the programmer, but it does provide some language mechanisms that help do that.

1.1. References to Functions

Perl allows the programmer to store a reference to a function inside a scalar value. This variable can later be dereferenced in order to invoke the function with any number of arguments.

By using this mechanism, one can implement callbacks, and make sure a wrapper function can invoke several helper functions which it will treat the same.

Closures

In perl it is possible to define dynamic subroutines, inside the code of the current scope. That scope can be a function or even another dynamic subroutine. These subroutines, which are sometimes referred to as closures, can see all the variables of the scope in which they were declared, even after the function that created them stopped running.

Closures enable the program to pass state information into callbacks that do not accept state information, and are generally a very convenient mechanism.

1.2. Modules and Packages

Packages are the perl terminology for namespaces. Namespaces enable the programmer to declare several functions or variables with the same name, and use all of them in the same code, as long as each one was declared in a different namespace. By using namespaces wisely, a programmer can be more certain his code will not clash with code from another developer. Moreover, packages are the basis for Perl's objects system.

Modules are files containing Perl code which can be loaded by programs or other modules. They allow the programmer to declare various functions in various packages (usually below the namespace that corresponds to the package name). Modules facilitate code reuse as the same module can be used by several modules and by several distinct programs.

1.3. Objects

An object is a set of variables and functions that are associated with this set. By calling these functions (commonly referred to as methods) one automatically has access to all the variables of the set. That way, it is possible to create and manage several instances of objects of the same class.

In Perl, every class resides in its own namespace. Perl enables various associations to be performed on entire classes. For instance, one class can inherit one or more classes, and thus have access to all of their methods.

By making a set of perl functions into a class, it is possible to make sure they can be instantiated and re-used. Furthermore, this class can later be expanded into a more powerful class, by making another class inherit it.

1.4. A Note about Source Files

In Perl, every module resides in his own file, and it is sometimes even necessary to put them inside a nested directory structure. (Note that it does not free a programmer from designating the module's name by a special header)

So far all of our scripts were self-contained, but now we may have to see code of several files at once. To ease this transition every file will contain the filename in its header comment. The filename will be given in UNIX notation, with slashes (/) and all, and will be relative to the directory in which the script is executed.

2.3. Dynamic References to Functions

It is possible to define a dynamic reference to a function. The code of its function is written as part of the assignment expression and can see all the variables in the scope in which it was defined. Here's an example:

2.3.1. Behaviour of Functions inside Functions

One can define such a reference to a function within another function. It is possible that this reference will be made accessible to the outside world after the outer function has terminated. In that case, the the inner function (which is called a closure) will remember all the relevant variables of the outer function.

Note that if two calls were made to the outer function, then the two resulting closures are by no mean related. Thus, changes in the variables of one closure will not affect the other. (unless, of course, they are global to both).

2.3.2. Demo: A Dispatch Function

It is possible to define more than one closure inside a function. Here is an example that uses closures to create a simple object-like construct. The code here borrows heavily from the book "Structure and Interpretation of Computer Programs" in which a similar code can be found written in Scheme.

2.3.3. Lambda Calculus

There's a model for computer programs called Lambda Calculus which proves that declaring closures and executing them is enough to perform all the operations provided by a full-fledged programming language. Perl supports Lambda-Calculus in a very straight-forward way, due to its support of lexical scoping.

Teaching Lambda-Calculus is out of the scope of this lecture, as well as pretty much off-topic. The interested reader is referred to the following links:

3. Perl Modules

Perl modules are namespaces that contain function and variables. Two distinct modules may each contain a function (or a variable) with the same name, yet the perl interpreter will be able to tell them apart. Furthermore, both functions can be invoked from the same code.

3.1. Declaring a Package

In order to designate that a code belongs to a different namespace you should use the package directive. For instance, if you want your module name to be "MyModule" your file should look something like this:

3.1.1. Where to find a module

A module is a separate file that may contain one or more different namespaces. That file is found in a place that corresponds to the module's name. To find the filename of the module relative to the script's directory, replace every :: with a slash and add ".pm" to the name of the last component.

For instance: the MyModule module will be found in the file "MyModule.pm"; the Hello::World module will be found in the file "World.pm" under the Hello sub-directory; etc.

3.2. Loading Modules and Importing their Functions

In order to have access to a module from within your script (or from within another module) you can use the use directive followed by the name of the module as it is deduced from its path. Here's an example: assume that the file "MyModule.pm" is this:

3.2.1. Accessing Functions from a Different Module

As could be seen from the last example, once the module has been use'd, its functions can be invoked by typing the full path of the package followed by :: and followed by the function name.

Note that if you are in package Foo and you are trying to access functions from package Foo::Bar, then typing Bar::my_func() will not do. You have to type the full path of the module. (Foo::Bar::my_func() in our case)

3.2.2. Exporting and Importing Functions

It is possible to make a functions of your module automatically available in any other namespace or script that uses it. To do so one needs to type the following code fragment near the beginning of the module:

What this fragment does is make the module inherit the Exporter module which is a special Perl module that can export symbols. Then it declares the special variable @EXPORT which should be filled with all the functions that one wishes to export.

Here is an example which has a module called "Calc" and a script that uses it:

As you can see, the script invokes the "gcd" function of the "Calc" module without having to invoke it with Calc::gcd(). Exporting functions like that should be used with care, as the function names may conflict with those of the importing namespace.

3.4. The "main" Namespace

One can access the main namespace (i.e, the namespace of the script), from any other namespace by designating main as the namespace path. For instance, main::hello() will invoke the function named "hello" in the script file.

Usually, the "main" part can be omitted and the symbols be accessed with the notation of ::hello() alone.

3.5. Difference between Namespaces and Modules

A namespace or package is a container for MyPackage::MySubPack::my_func() symbols.

A module, on the other hand, is a file that can contain any number of namespaces, or simply drop everything into the current namespace (although it shouldn't).

It is possible to switch to other packages using the package statement. However, you then have to remember not to use them, because Perl will look for a file corresponding to that name.

A module can put itself in a completely different namespace than its designated module name. (e.g: a module loaded with use TheModule; can declare all of its identifiers in the CompletelyDifferentPackage namespace.)

4.1. How it Works behind the Scenes

An object is basically a reference to a hash where the hash members are the object member variables. That reference is "blessed" to be associated with a module. Whenever the programmer makes a method call, the methods are being searched starting from that module. That module is the object's class.

Method calls in perl are done using the $object_ref->method_name(@args) notation. Note that in Perl, passing the object reference is done explicitly and it is the first argument passed to the function.

4.2. Object Use

Let's demonstrate the object use cycle on a very useful Perl class called Data::Dumper. This class accepts a set of perl data structures, and renders them into a string which is an easy-to-read Perl representation of them.

Here's a program that uses it to display a perl data structure on the screen:

4.3.1. The Constructor

Here is an example, constructor for the class Foo:

## Foo.pm#package Foo;
use strict;
use warnings;
sub new
{
# Retrieve the package's string.# It is not necessarily Foo, because this constructor may be# called from a class that inherits Foo.my$class = shift;
# $self is the the object. Let's initialize it to an empty hash# reference.my$self = {};
# Associate $self with the class $class. This is probably the most# important step.bless$self, $class;
# Now we can retrieve the other arguments passed to the# constructor.my$name = shift || "Fooish";
my$number = shift || 5;
# Put these arguments inside class members$self->{'name'} = $name;
$self->{'number'} = $number;
# Return $self so the user can use it.return$self;
}
1;

4.3.3. Object Inheritance

Now, let's suppose we would like to create a class similar to Foo, that's also keeps track of the number of times its name was assigned. While we can write a completely different object, we can inherit from Foo and use what we already have in place.

Here's a class derived from Foo that has a method assign_name_ext that keeps track of the number of times it was called, and a method get_num_times_assigned that retrieves this number:

4.4. Object Utility Functions - isa() and can()

isa() is a special method that can be used on every object. When invoked with the name of a package as an argument, it returns whether or not this object inherits from this package (directly or indirectly).

can() is a method that determines if an object can execute the method by the name given to it as argument.