Developer Forums | About Us | Site Map
Search  
HOME > TUTORIALS > SERVER SIDE CODING > PERL TUTORIALS > THE ROAD TO BETTER PROGRAMMING: CHAPTER 5 MODULES AND OBJECTS


Sponsors





Useful Lists

Web Host
site hosted by netplex

Online Manuals

The road to better programming: Chapter 5 Modules and objects
By Teodor Zlatanov - 2004-03-01 Page:  1 2 3 4 5 6 7 8

How to use OOP in Perl

Believe it or not, OOP in Perl is not hard on a beginner or intermediate level, and even advanced usage is not that complicated. You might think otherwise based on all the discussion we've had so far about the intricate workings of OOP. Perl, however, delights in placing as few restrictions on the programmer as possible. Perl OOP is, if you'll excuse the analogy, like a barbecue. Everyone brings their own cut of meat and cooks it the way they like it. Even the communal spirit of a barbecue is there, as data can be easily shared between unrelated objects.

The first step we must take is to understand Perl packages. Packages are like namespaces in C++ and libraries in Java: fences meant to corral data into specific areas. Perl packages, however, are only meant as advisories to the programmer. By default, Perl does not restrict data exchange across packages (although the programmer may do so with via lexical variables).

Listing 1. Package names, switching packages, sharing data between packages, package variables


#!/usr/bin/perl
# note: the following code will generate warnings with the -w switch, 
# and won't even compile with "use strict".  It is meant to demonstrate
# package and lexical variables.  You should always "use strict".
# pay attention to every line!
# this is a global package variable; you shouldn't have any with "use strict"
# it is implicitly in the package called "main" 
$global_sound = "
";
package Cow;                              # the Cow package starts here
# this is a package variable, accessible from any other package as $Cow::sound
$sound = "moo";
# this is a lexical variable, accessible anywhere in this file
my $extra_sound = "stampede";
package Pig;                              # the Pig package starts, Cow ends
# this is a package variable, accessible from any other package as $Pig::sound
$Pig::sound = "oink";                     
$::global_sound = "pigs do it better";    # another "main" package variable
# we're back to the default (main) package
package main;
print "Cows go: ", $Cow::sound;           # prints "moo"
print "\nPigs go: ", $Pig::sound;         # prints "oink"
print "\nExtra sound: ", $extra_sound;    # prints "stampede"
print "\nWhat's this I hear: ", $sound;   # $main::sound is undefined!
print "\nEveryone says: ", $global_sound; # prints "pigs do it better"

Note that the file-scoped lexical variable $extra_sound is accessible in all three packages ("main", "Pig", and "Cow") because they are all defined within the same file in this example. Normally, each packages is defined within its own file, ensuring that lexical variables are private to the package. Thus, encapsulation can be achieved. (Run "perldoc perlmod" for more information.)

Next, we have to relate packages to classes. As far as Perl is concerned, a class is just a fancy package (objects, on the other hand, are specifically created with the bless() function). Again, Perl relaxes the OOP rules so that the programmer is not constrained by them.

The new() method is the conventional name for the class constructor (although you may use any name you want, in typically relaxed Perl fashion). It is invoked whenever a class is instantiated into an object.

Listing 2. A barebones class


#!/usr/bin/perl -w
package Barebones;
use strict;
# this class takes no constructor parameters
sub new
{
  my $classname = shift;  # we know our class name
  bless {}, $classname;   # and bless an anonymous hash
}
1;

You can test this code for yourself by putting the code in Listing 2 in a file called Barebones.pm in any directory, and running the following from that directory (meaning, "include the current directory in the library path, use the Barebones module, and create a new Barebones object"):


perl -I. -MBarebones -e 'my $b = Barebones->new()'

For instance, you can put print statements inside the new() method so you can see what the $classname variable holds.

If you invoke Barebones::new() instead of Barebones->new(), the class name will not be passed to new(). In other words, new() will not act as a constructor, but as a plain function.

You may wonder why $classname needs to be passed in. Why not just say bless {}, "Barebones";? Because of inheritance, this constructor may be called by a class that inherits from Barebones, but is not called Barebones. You would be blessing the wrong thing with the wrong name, and that is a bad idea in OOP.

Every class needs member data and methods other than new(). Defining those is as easy as writing a few procedures.

Listing 3. A class with member data and methods


#!/usr/bin/perl -w
package Barebones;
use strict;
my $count = 0;
# this class takes no constructor parameters
sub new
{
  my $classname = shift;  # we know our class name
  $count++;               # remember how many objects
  bless {}, $classname;   # and bless an anonymous hash
}
sub count
{
  my $self = shift;       # this is the object itself
  return $count;
}
1;

You can test this code with:



perl -I. -MBarebones -e 'my $b = Barebones->new(); Barebones->new(); print $b->count'

and you should get the result '2'. The constructor is invoked twice, and it modifies a lexical variable ($count) that is confined to the scope of the Barebones package, not to each Barebones object. Object-local data should be stored in the object itself. In the case of Barebones, that is the anonymous hash blessed as an object. Note how we can access the object whenever its methods are called, because a reference to the object is the first parameter passed to those methods.

There are a few special methods such as DESTROY(), and AUTOLOAD(), which are invoked automatically by Perl under certain conditions. AUTOLOAD() is the catch-all method used to allow dynamic method names. DESTROY() is the object destructor, but it should not be used unless you really, really need it. Using destructors in Perl usually indicates that you are still thinking like a C/C++ programmer.

Let's look at inheritance. It is done in Perl by changing the @ISA variable. You just assign a list of class names to that variable. That's it. You can put anything in @ISA. You can make your class a child of Satan. Perl doesn't care (although your priest, minister, imam, rabbi, etc. might).

Listing 4. Inheritance


#!/usr/bin/perl -w
package Barebones;
# add these lines to your module's beginning, before other code or
# variable declarations
require Animal;                      # the parent class
@ISA = qw(Animal);                   # announce we're a child of Animal
# note that @ISA was left as a global default variable, and "use
# strict" comes after its declaration.  That's the easiest way to do it.
use strict;
use Carp;
# make your new() method look like this:
sub new
{
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self  = $class->SUPER::new();  # use the parent's new() method
  bless ($self, $class);             # but bless $self (an Animal) as Barebones
}
1;

These are the very basics of OOP in Perl. There is a lot more in the language that you should explore. Many good books have been written on the subject. Consult Resources for a sampling.



View The road to better programming: Chapter 5 Modules and objects Discussion

Page:  1 2 3 4 5 6 7 8 Next Page: h2xs: your new best friend

First published by IBM developerWorks


Copyright 2004-2024 GrindingGears.com. All rights reserved.
Article copyright and all rights retained by the author.