Please Support The Fight Against EU Software Patents
"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration." -- Professor Edsger Dijkstra

Object Oriented Perl

Object oriented programming is hard to sum up in a single sentence. But if you know what it is, you know that it's a very powerful tool. You probably also know that perl is not exactly renowed for providing object oriented programming facilities.

Indeed, if you're thinking of doing some OO perl, your first thought should be: why is perl a good language for this? There are valid reasons: perhaps perl is the language you know best, or you might have access to a big perl codebase that already does most of what you want. Generally speaking, though, if you're able to choose, you should probably choose something else.

That out of the way, let's get stuck in to some object orientation! When I started doing OO perl I didn't find any guides that really worked for me, so I'm going to share the fruits of my labour in the hope that I'll help someone else in a similar situation.

Ground Rules

One of the main areas where object oriented programming helps is in structuring large projects. So, I'm going to assume that at least a few thousand lines of code is involved. A few thousand lines of perl can very quickly become unmanageable; care is certainly needed. It's possible to help structure things with OO technology, but you need to exercise restraint.

Essentially, if you're going to do OO perl, you more or less have to pretend that you're using a stricter language like C++ and Java. The general style guidelines that apply to those languages should apply to your perl code, too. In particular:

This last point is particularly important in perl. It's very easy to write perl code, but in OO programming that becomes as much a disadvantage as an advantage. Using the same regular expression over and over again is bad. Stringing together the same primitives in the same way over and over again is very bad. Perl makes it easy to get what you want by writing what you want, but to write a good OO program you need to get what you want by abstracting the key problem features as classes. Only then do you get the payoff: a better program structure and code that's easy to maintain.

Here's a concrete example. Reading a delimited text file in perl is easy; it's a matter of a few lines of code. In a short script, that's fine, but in a large project, it's disastrous. The same few lines will end up repeated over and over again. If there's a type of file you need to read, there needs to be a class for reading it. If there are several similar types, they need classes with a common interface so you can pick and choose between them.

Here are some guidelines:

It may sound like these guidelines rule out some of the best features of perl, and indeed that's correct if you're writing a 100-line script. Once the project gets into the thousands of lines, these features become problematic. They need hiding inside classes or avoiding altogether.

Example Class

With all that out of the way, it's time to touch on how you write an actual class. In perl an object is actually an instance of one of the primitive types that's been 'blessed' into a particular class. That's more or less all there is to it.

Most guides suggest using a hashref as the base type for your classes. Personally I think this is a bad idea, because it encourages people to access the private members of the class. Instead, I always use an arrayref. If I want someone to have access to a data member, I write an accessor function.

Here's a class representing a square:

# The package name will become the class name
package Square; 

use strict;
use warnings; # Always a good idea

# public Square new(double size)
# Instantiate a square of a specified size.
sub new
{
   my($package, $size) = @_;

   die unless scalar @_ == 2;

   my $this = [
      $size # Length of side of the square
   ];

   bless $this, $package or die;

   return $this;
}

# private double _GetSize()
# Get the side length. This method is private, denoted by the underscore.
# This is not enforced, but at least it is clearly indicated.
sub _GetSize
{
   my($this) = @_;

   die unless scalar @_ == 1;

   return $this->[0];
}

# public double Area()
# Get the area of the square.
sub Area
{
   my($this) = @_;

   die unless scalar @_ == 1;

   return $this->_GetSize() * $this->_GetSize();
}

1; # Package needs to return true

This should be placed in a file called Square.pm and can be used as follows:

use Square;

my $square = Square->new(7);
print "The square area is ", $square->Area(), "\n";

Writing explicit accessor functions in this way takes a little work, but the benefits are huge. Once you start dictating how a class should be used, you can stop worrying about implementation and start concentrating on interfaces. And that's where object orientation really begins to get useful.

Conclusion

Perl's object orientated facilities are not great, but with a bit of discipline you can use them to your advantage. Careful structuring and class design can really pay off when it comes to keeping your code maintained.

So there you have it: object oriented perl. A bizarre concept, a bizarre implementation, but in the end it does actually work.