Augustina's Technological Blog

Technology, Perl, Linux, and a Woman's perspective on the FOSS community

An Introduction to Object-Oriented Perl

with 2 comments

I’ve been using Perl for a few years now and I am finally getting to a place where I’m working with more complex problems. Traditionally I’ve written little utility scripts or handlers for small specific tasks. In my current position, one of my roles is writing ad-hoc scripts for bulk reporting and bulk updates to a large number of database records for client requests. As I’m passing some of these duties on to my coworkers, I realized I needed a template to ensure consistency and to make their lives easier. I’ve also been tasked with a larger project for which I’ve decided the solution is to make a single Object-Oriented API in our code base that can be called by many different sources.

My original training is in Java/C++ and Object-Oriented Design. I wanted to approach both of these problems using my OO background, but I was having trouble grasping how OO really works in Perl. I’ve scoured the internet and poured through books, and none of them could really answer my questions. Finally, I sat down with someone recently who answered my “why why why” questions (and who also proofread this entry for accuracy! Thanks Dave!!). I decided I should document this here in hopes that it might help others who are in the same conundrum.

This article will be most useful if you already understand OO and you understand Perl but you just want to know from a bottom up perspective how OO works in Perl.

Key Concepts

Unlike languages like C++ and Java where Object-Orientation was considered during the language development, in Perl it was more of an afterthought.

Bless

Bless is a built-in Perl function that turns any reference into an object. While generally it’s good practice to use hash references, there are many differing schools of thought on Perl OO, including inside-out objects. These techniques are beyond the scope of this particular article (bad OO pun haha) so I won’t discuss them here.

There are 2 key differences between references and blessed references (aka objects). An object contains an OBJECT flag telling the interpreter that its an object. An object also contains a string with the name of its class so the interpreter can look up methods called on the object that are defined in its class.

When you instantiate an object in your executable Perl code, the Perl interpreter stores the class name in the object data. When a method is called on the object instance, Perl attempts to resolve the method at runtime. Using the class name, the interpreter looks for the method in the class definition. If it does not find the method, it looks in @ISA to see if the class is a child and if the method is defined in the parent class. If it does not find the method defined for the class, the interpreter throws a “Can’t locate object method” exception.

Here are examples using Devel::Peek to view what a reference and an object looks like:

First examine what a hash reference looks like:

perl -MDevel::Peek -wle 'my $not_an_object = {}; print Dump($not_an_object)'

Output:

SV = RV(0x90e492c) at 0x90e4920
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x90e4880
SV = PVHV(0x90ef340) at 0x90e4880
REFCNT = 1
FLAGS = (SHAREKEYS)
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0

Now examine what an blessed hash reference (aka object) looks like:

perl -MDevel::Peek -wle 'my $object = bless {}, "main"; print Dump($object)'

Output:

SV = RV(0x979d92c) at 0x979d920
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x979d880
SV = PVHV(0x97a8340) at 0x979d880
REFCNT = 1
FLAGS = (OBJECT,SHAREKEYS)
STASH = 0x979d770 "main"
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0

Notice the second FLAGS entry and the STASH entry. STASH contains both the string of the class name and the address where the string is stored in memory. FLAGS contains the value OBJECT which tells the Perl interpreter that $object is an object.

Intrinsic vs. Explict Methods

In Perl, a method does not intrinsically know what object or class it’s called on. When a method is called, the Perl interpreter either passes a reference to that object or the class name as the first argument. When writing methods that take arguments, the first argument passed in by the interpreter is the object reference or the class name depending on whether the method was called by an object or by the class itself. For instance, the new() constructor is called on the class so the first argument the interpreter passes in is a string containing the class name. For a method you define called by an object instance, the interpreter passes in a reference to that object.

While it’s good practice to call the first argument $self or $me, you can call it whatever you want.

Here’s are two examples of handling arguments in methods:

sub my_method {
my $self = shift;
my ($arg1, $arg2) = @_;
}

sub my_method {
my ($self, $arg1, $arg2) = @_;
}

Here’s an example of calling the method, for this example the class is “MyClass”.

my $my_class = MyClass->new();

$my_class->my_method($arg1, $arg2);

When calling a class method without an object instance, the first argument is a string representing the name of the class.

MyClass->my_method($arg1, $arg2);

Class Methods vs. Object Methods

In Perl, you don’t have to instantiate an object to call its class methods, so you have to provide your own enforcement if this is a possible risk.

When a method is called by a class, the first argument passed is a string containing the name of the class. When a method is called by an object, the first argument is a reference to the object. To enforce calling methods by object, check that the first argument passed is a reference.


die "Please call this method on an object instance." if (! ref $self);

Unenforced Privacy

There are no private methods in Perl except by convention. To designate a method as private, the general practice is to begin the name with an _ character. While this does not prevent use of this method in other contexts, it makes your code and your intentions easier to read.

sub _my_private_method {}

sub my_public_method {}

Data Attributes

One of the advantages to using a blessed hash ref for your object is that you can manage basic data attributes without using accessor methods or having to maintain a long list of variables. I believe accessor methods should be used under two circumstances: 1. when they add some value or additional functionality or enforceability with regards to data types and data values, and 2. when a data attribute needs to be modified external to the class definition. When dealing with simple values used internal to the class definition, maintaining a long list of variables and getter/setter methods is overkill. This is my opinion and I’m sure there are plenty of others out there that differ, so do what works best for the problem you are trying to solve. I’m just presenting an alternative that was shown to me that I’ve found to be pretty handy.


$self->{NAME} = $name;

Instead of having to create and maintain a get/set_name method, your object can access it’s own “name” with $myobject->{NAME}.

Garbage Collection

Once an object goes out of scope, the Perl interpreter calls DESTROY on it prior to dereferencing the memory. Unless your class has specific requirements for what needs to happen when the object is destroyed, you don’t need to implement the destroy method.

To implement the DESTROY method, define a method called DESTROY in all caps.

Perl does not automatically call DESTROY on super classes. To DESTROY a super class, you must explicitly call $self->SUPER::DESTROY.

How To

As stated in the previous section, there are many philosophies about how to do Object Oriented Perl. The intent of this article is provide basic instructions for getting started with writing a simple class and to explain some of the Perl internals. The reason for this is because I was having a hard time finding the information I needed and up-to-date examples. Once you’ve gotten a general idea of the basics, it’s worthwhile to explore different OO Perl philosophies.

1. Create a class file ending in .pm

For this example, create a file called MyClass.pm and save it where Perl can find it.

Define a new() method to bless your passed in reference and assign it to the class. Define methods as appropriate and return 1 at the end.


package MyClass;
use strict;
use warnings;

sub new {
# first argument is the class name
my ($class, %args) = @_;

# create an anonymous hash ref called $self
# bless $self to set it as obj with class name $class
# return obj ref
my $self = bless {}, $class;

# call a method on $self to set an initial value
if (defined $args{name})
{
$self->set_name($args{name});
# alternatively we can set the name using
# $self->{NAME} = $name;
} else {
die "Please specify a name for the $class instance.";
}

# return the obj instance
return $self;
}

sub set_name {
my ($self, $name) = @_;

if (! ref $self) # if called as a class method, $self is a string, not a ref
{
die "Please call this method on an object instance.";

} else {
# assign class data attributes to keys within the $self hash
$self->{NAME} = "My name is " . $name;
}
}

sub print_name {
my ($self) = @_;
print $self->{NAME}, "\n";
}

1;

2. Create a Perl executable file ending in .pl. Instantiate your class by creating a variable and using the new() method. Call a method on your class to see if it works!


#!/usr/bin/perl -w
use strict;
use MyClass;

# create an object by instantiating MyClass
my $object = MyClass->new(name => 'Eugene');

# call an object method on MyClass
$object->print_name();

# calling a class method returns an error
MyClass->set_name('Marsha');

Advertisements

Written by missaugustina

June 6, 2010 at 10:31 pm

Posted in Perl, Programming

2 Responses

Subscribe to comments with RSS.

  1. Overall, a good and very thorough summary of OO in Perl! Just a few points to add:

    – Under “Intrinsic vs. Explict Methods”, you covered that Perl doesn’t maintain a strong distinction between class and instance methods, but didn’t mention that it’s the -> operator that makes it a method call rather than a function call. In your examples, MyClass::new would call MyClass’s sub new, but pass it neither a class name nor a reference to an instance.

    The heart of OO in Perl is that -> passes whatever is to its left as the first parameter to the function on its right. For most practical purposes, “$obj->method” is equivalent to “ClassName::method($obj)”; the only difference is that “$obj->method” recognizes inheritance (via @ISA, as you said) and “ClassName::method($obj)” does not.

    – For “Data Attributes”, you can easily generate accessors for a list of attributes with code along the lines of

    BEGIN {
    no strict ‘refs’;
    for my $attr (qw( foo bar baz )) {
    *$attr = sub {
    $_[0]->{$attr} = $_[1] if defined $_[1];
    return $_[0]->{$attr};
    };
    }
    }

    …or there are also several attribute-generating modules on CPAN if you prefer not to roll your own.

    – Your final example can all be done within a single file, just remove the line “use MyClass;” from the .pl and append the code you gave for the .pm to the .pl. Multiple packages can go into the same file (or a single package can be spread across multiple files, for that matter) and the only thing “use” is needed for is to pull in other files – it actually has nothing to do with packages/classes beyond the convention of putting packages into a file with the same name as the package.

    – Finally, if you’re serious about OO in the current age of Perl, you should definitely take a look at Moose. It’s growing in popularity very rapidly because it provides a much richer OO experience which, coming from Java/C++, you’ll probably find more familiar. (On the other hand, I’m one of the few outliers who prefers blessing my own references, and I do believe that, even if you use Moose, understanding the information you’ve presented here is still essential to getting the most out of it.)

    Dave Sherohman

    June 8, 2010 at 6:45 am

  2. Look like Dave stressed out a vital point here. I’m only in the C,C++ and Java level. Still, I take his ideas as a very helpful one for my preparation in the Com Sci field.

    steve blogger

    November 2, 2012 at 4:14 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: