Object-Oriented Programming

A module is a Perl package, objects in Perl are based on references to data items within a package. An object in Perl is simply a reference to something that knows which class it belongs to. As in other languages you declare a class and then create objects of that class. All objects of a particular class behave in a certain way, which is governed by the methods of that class. You can create new classes by defining new ones or by inheriting properties from an existing class.

There are three important rules

The inheritance feature in Perl is not the same as in other languages, Perl classes inherit methods (subroutines) only, you must implement your own mechanisms for data inheritance. Because each class is a package, it has its own name space with its own associative array of symbols names. Each class can therefore use its own independedt set of symbols names. You can address the variables in a class using the double colon (::) operator, members of a class are addressed as $class::$member.

Creating a Class

Remembering that a module is a Package and a Pacakge is a class the file extension for the class will be .pm, a perl module file must have a 1; to terminate the package.

Basic Package

package Cocoa;
#
#   put required statements in for all required or imported packages
#

#
#   Just add your code here
#

1;     # terminate the package with the required 1;

Blessing a Constructor

A constructor is a Perl subroutine in a class that returns a reference to something that has the class name attched to it. Connecting a class name with a reference is reffered to as blessing an object because the function to establish the connection is called bless.

Blessing an object

package Cocoa;

sub new {
   my $this = {};     # create an anonymous hash, and #self points to it
   bless this;        # Connect the hash to the package Cocoa
   return this;       # Return the reference to the hash
}

1;     # terminate the package with the required 1;

## To create a Cocoa object
push (@INC,'pwd');             # add the local directory to the search path @INC (where your package is located
use Cocoa;                     # include the Cocoa package using the @INC path/s
$cup = new Cocoa;              # Create the Cocoa object

# $cup = Cocoa->new();         # There are many ways to create a object
# $cup = Cocoa::new();

Forcing how to create an object

package Cocoa;

sub new {
   my $this = shift;                    # Get the class name (used when calling for another class)
   my $class = ref($this) || $this;     # If the class exists, use it else use the reference

   my $this = {};
   bless $this, $class;                 # Use class name to bless() reference

   $this->doInitialization();           # call a function within the object         
   return this;       
}

1;     # terminate the package with the required 1;

Note: you are now forced to create an object by using either

$cup = new Cocoa;             
$cup = Cocoa->new();        
$cup = Cocoa::new();

Instance Variables

The arguments to a new() function for a constructor are called instance variables, they are used to do initialization for each instance of an objects as it created. You can either use an anonymous array or an anonymous hash to hold instance variables.

Instance Variables ## Cocoa Package (Cocoa.pm)
package Cocoa;

sub new {
   my %parm = @_;
   my $this = {};

   $this->{'Name'} = $parm{'Name'};
   $this->{'x'} = $parm{'x'};
   $this->{'y'} = $parm{'y'};

   bless $this, $type;
}

1;

## Main Program (Test.pl)
use Cocoa;

$cup = Cocoa::new('Name' => 'top', 'x' => 10, 'y' => 20);

print "Name = $cup->{'Name'} \n";
print "x = $cup->{'x'} \n";
print "y = $cup->{'y'} \n"

Methods

A method is simply a subroutine, there is no special syntax for method definition. Perl has two types of methods:

A static method applies functionality to the entire class as a whole because it uses the name of the class. Constructors are static methods

A virtual method first shifts the first argument into a self or this variable and then use that shifted value as an ordinary reference.

Inheritance in Perl is through the @ISA array, this array contains the names of the classes (packages) to look for methods in other classes in if a method in the current package is not found.

Example
## Package (Cocoa.pm)
package Cocoa; require Exporter; @ISA = qw(Exporter);                                 # set the @ISA array with the name of the Exporter class
# to look for
@EXPORT = qw(setImports, declareMain, closeMain);    # Export the methods in to the export array # This routine creates the references for imports in Java functions sub setImports{ my $class = shift @_; my @names = @_; foreach (@names) { print "import " . $_ . ";\n"; } } # This routine declares the main function in a Java script sub declareMain { my $class = shift @_; my ( $name, $extends, $implements) = @_; print "\n public class $name"; if ($extends) { print " extends " . $extends; } if ($implements) { print " implements " . $implements; } print " { \n"; } # # This routine declares the main function in a Java script # sub closeMain { print "} \n"; } # This subroutine creates the header for the file. sub new { my $this = {}; bless $this; return $this; } 1; ## Main Program (Test.pl)
use Cocoa; $cup = new Cocoa; $cup->setImports( 'java.io.InputStream', 'java.net.*'); $cup->declareMain( "Msg" , "java.applet.Applet", "Runnable"); $cup->closeMain(); ## Could be rewritten as Cocoa::setImports($cup, 'java.io.InputStream', 'java.net.*'); Cocoa::declareMain($cup, "Msg" , "java.applet.Applet", "Runnable"); Cocoa::closeMain($cup);

Destructors

Perl tracks the number of links to objects, when the last reference to an object is freed to the memory poolo, the object is automatically destroyed. If you want to capture control just before the object is freed, you can define a destroy() method in your class, you can use this method to perform any clean up.

Example

sub DESTROY {

## Add your code here

}

Inheritance

Methods in classes are inheriated with the paths in the @ISA array, variables must be explicity setup for inheritance.

Example
## Package (Bean.pm)
package Bean;

require Exporter;

@ISA = qw(Exporter);
@EXPORT = qw(setBeanType);

# Constructor
sub new { my $type = shift; my $this = {}; $this->{'Bean'} = 'Colombian'; bless $this, $type; return $this; } # This subroutine sets the class name sub setBeanType{ my ($class, $name) = @_; $class->{'Bean'} = $name; print "Set bean to $name \n"; } 1; ## Package (Coffee.pm) - file to illustrate inheritance. package Coffee; require Exporter; require Bean; @ISA = qw(Exporter, Bean); @EXPORT = qw(setImports, declareMain, closeMain); # set item sub setCoffeeType { my ($class,$name) = @_; $class->{'Coffee'} = $name; print "Set coffee type to $name \n"; } # constructor sub new { my $type = shift; my $this = Bean->new(); ##### <- LOOK HERE!!! - Inheritance at work #### $this->{'Coffee'} = 'Instant'; # unless told otherwise bless $this, $type; return $this; } 1; ## Main Program (Test.pl) push (@INC,'pwd'); use Coffee; $cup = new Coffee; print "\n -------------------- Initial values ------------ \n"; print "Coffee: $cup->{'Coffee'} \n"; print "Bean: $cup->{'Bean'} \n"; print "\n -------------------- Change Bean Type ---------- \n"; $cup->setBeanType('Mixed'); print "Bean Type is now $cup->{'Bean'} \n"; print "\n ------------------ Change Coffee Type ---------- \n"; $cup->setCoffeeType('Instant'); print "Type of coffee: $cup->{'Coffee'} \n";

Overriding Methods

It is possible in Perl (as in other languages) to override methods, in order to call the inheriated method you use the SUPER:: pseudo-class reserved word. In the example below there are two toString methods one is overriden.

Overriding example
## Main Program (test.pl)
use pkgOne; $test = new pkgOne; print $test->toString(); ## Package (pkgOne.pm)
package pkgOne; require Exporter; require pkgTwo; @ISA = (Exporter, pkgTwo);                ## Inheritance path @EXPORT = qw(toString); sub new { my $class = shift; my $this = pkgTwo->new();               ## Inheritance here bless $this, $type; return $this; } sub toString {                            ## overriding pkgTwo toString method    my $this = shift;
   printf("This is pkgOne toString\n");
   print $this->SUPER::toString() . "\n";  ## A call to super class pkgTwo method toString } 1; ## Package (pkgTwo.pm)
package pkgTwo; require Exporter; @ISA = (Exporter); @EXPORT = qw(toString); sub new { my $type = shift; my $this = {}; bless $this, $type; return $this; } sub toString { print "pkgTwo toString being called by SUPER::\n"; } 1;