Object-oriented programming (often called OOP) helps programmers run code sooner and maintain it easier at the cost of making the resulting programs slower. That is to say, a typical program written in an OO language will normally run more slowly than the corresponding one written in a language without objects.
So why would anyone want their programs to run more slowly? Your programs will take less time to read, write, debug, and maintain, and on large projects, these factors are important. How much slowdown are we talking about? Well, that depends. But in general, the more heavily you use objects, the more it will save time for the programmer, and the more it will cost time at runtime. Still, you should remember that computers keep getting faster. Even if using OOP slows down your program, using next year’s hardware will probably make up for it.
The benefits of OOP become worthwhile when your program (including all external libraries and modules) exceeds about N lines of code. Unfortunately, nobody can agree on what the value of N is, but for Perl programs, it’s arguably around 1,000 lines of code. If your whole program is only be a couple hundred lines of code, using objects is probably a waste.
Like references, Perl’s object architecture was grafted on after a substantial amount of existing pre-Perl5 code was already in use, so we had to ensure that it wouldn’t break existing syntax. Amazingly, the only additional syntax to achieve object nirvana is the method call, introduced shortly. But the meaning of that syntax requires a bit of study, so let’s proceed.
The Perl object architecture relies heavily on packages, subroutines, and references, so if you’re skipping around in this book, please go back to the beginning. Ready? Here we go.
Obviously, the castaways can’t survive on coconuts and pineapples alone. Luckily for them, a barge carrying random farm animals crashed on the island not long after they arrived, and the castaways began farming and raising animals.
Let’s let those animals talk for a moment:
sub Cow::speak { print "a Cow goes moooo!\n"; } sub Horse::speak { print "a Horse goes neigh!\n"; } sub Sheep::speak { print "a Sheep goes baaaah!\n"; } Cow::speak; Horse::speak; Sheep::speak;
This results in:
a Cow goes moooo! a Horse goes neigh! a Sheep goes baaaah!
Nothing spectacular here: simple subroutines, albeit from separate packages, and called using the full package name. Let’s create an entire pasture:
sub Cow::speak { print "a Cow goes moooo!\n"; } sub Horse::speak { print "a Horse goes neigh!\n"; } sub Sheep::speak { print "a Sheep goes baaaah!\n"; } my @pasture = qw(Cow Cow Horse Sheep Sheep); foreach my $beast (@pasture) { &{$beast."::speak"}; # Symbolic coderef }
This results in:
a Cow goes moooo! a Cow goes moooo! a Horse goes neigh! a Sheep goes baaaah! a Sheep goes baaaah!
Wow. That symbolic coderef dereferencing there in the body of the
loop is pretty nasty. We’re counting on
no
strict
'refs
' mode, certainly not recommended for larger
programs.[34]
And why was that necessary? Because the name of the package seems
inseparable from the name of the subroutine you want to invoke within
that package.
Or is it?
A
class is a group of things with similar
behaviors and traits. For now, let’s say that
Class->method
invokes subroutine
method
in package Class
.
That’s not completely accurate, but
you’ll catch on one step at a time.
Let’s use it like so:
sub Cow::speak { print "a Cow goes moooo!\n"; } sub Horse::speak { print "a Horse goes neigh!\n"; } sub Sheep::speak { print "a Sheep goes baaaah!\n"; } Cow->speak; Horse->speak; Sheep->speak;
And once again, this results in:
a Cow goes moooo! a Horse goes neigh! a Sheep goes baaaah!
That’s not fun yet. You’ve got the same number of characters, all constant, no variables. However, the parts are separable now:
my $beast = "Cow"; $beast->speak; # invokes Cow->speak
Ahh! Now that the package name
is separated from the subroutine name, you can use a variable package
name. This time, you’ve got something that works
even when use strict 'refs
' is enabled.
Take the arrow invocation and put it back in the barnyard example:
sub Cow::speak { print "a Cow goes moooo!\n"; } sub Horse::speak { print "a Horse goes neigh!\n"; } sub Sheep::speak { print "a Sheep goes baaaah!\n"; } my @pasture = qw(Cow Cow Horse Sheep Sheep); foreach my $beast (@pasture) { $beast->speak; }
There! Now all the animals are talking, and safely at that, without the use of symbolic coderefs.
But look at all that common code. Each speak
routine has a similar structure: a print
operator
and a string that contains common text, except for two words. One of
OOP’s core features minimizes common code: if you
write it only once, you’ll save time. If you test
and debug it only once, you’ll save more time.
Now that you’ve learned more about what the method invocation arrow actually does, we’ve got an easier way to do the same thing.
Class->method(@args)
attempts to invoke the subroutine Class::method
as:
Class::method("Class", @args);
(If the subroutine can’t be found, inheritance kicks
in, but you’ll learn about that later.) This means
that you get the class name as the first parameter or the only
parameter, if no arguments are given. You can rewrite the
Sheep
speaking subroutine as:
sub Sheep::speak { my $class = shift; print "a $class goes baaaah!\n"; }
The other two animals come out similarly:
sub Cow::speak { my $class = shift; print "a $class goes moooo!\n"; } sub Horse::speak { my $class = shift; print "a $class goes neigh!\n"; }
In each case, $class
gets the value appropriate for that subroutine. But once again, you
have a lot of similar structure. Can you factor out that commonality
even further? Yes—by calling another method in the same class.
You can call out from
speak
to a helper method called
sound
. This method provides the constant text for
the sound itself:
{ package Cow; sub sound { "moooo" } sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } }
Now, when you call Cow->speak
, you get a
$class
of Cow
in
speak
. This, in turn, selects the
Cow->sound
method, which returns
moooo
. How different would this be for the
Horse
?
{ package Horse; sub sound { "neigh" } sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } }
Only the name of the package and the specific sound change. So can
you share the definition for speak
between the cow
and the horse? Yes, with inheritance!
Now let’s define a common subroutine package called
Animal
with the definition for
speak
:
{ package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } }
Then, for each animal, you can say it inherits from
Animal
, along with the animal-specific sound:
{ package Cow; @ISA = qw(Animal); sub sound { "moooo" } }
Note the added @ISA
array. We’ll
get to that in a minute.
What happens when you invoke Cow->speak
now?
First, Perl constructs the argument list. In this case,
it’s just Cow
. Then Perl looks
for Cow::speak
. That’s not there,
so Perl checks for the inheritance array
@Cow::ISA
. It’s there, and
contains the single name Animal
.
Perl next checks for speak
inside
Animal
instead, as in
Animal::speak
. That found, Perl invokes that
subroutine with the already frozen argument list, as if you had said:
Animal::speak("Cow");
Inside the
Animal::speak
subroutine,
$class
becomes Cow
as the first
argument is shifted off. When you get to the step of invoking
$class->sound
while performing the
print
, it looks for
Cow->sound
:
print "a $class goes ", $class->sound, "!\n"; # but $class is Cow, so... print "a Cow goes ", Cow->sound, "!\n"; # which invokes Cow->sound, returning "moooo", so print "a Cow goes ", "moooo", "!\n";
and you get your desired output.
This
magical @ISA
variable (pronounced
“is a” not
“ice-uh”), declares that
Cow
“is a”
Animal
.[35]
Note that it’s an array, not a simple single value,
because on rare occasions it makes sense to have more than one parent
class searched for the missing methods. You’ll learn
more about that later.
If
Animal
also had an @ISA
, you
can check there too.[36] Typically, each @ISA
has only one
element (multiple elements means multiple inheritance and multiple
headaches), so you get a nice tree of inheritance. (There is also
inheritance through UNIVERSAL
and
AUTOLOAD
; see the perlobj
manpage for the whole story.)
When you turn on use strict
, you’ll get complaints on
@ISA
because it’s not a variable
containing an explicit package name, nor is it a lexical
(my
) variable. You can’t make it
a lexical variable though: it has to belong to the package to be
found by the inheritance mechanism.
There are a couple of straightforward ways to handle the declaration
and setting of @ISA
. The easiest is to just spell
out the package name:
@Cow::ISA = qw(Animal);
You can also allow it as an implicitly named package variable:
package Cow; use vars qw(@ISA); @ISA = qw(Animal);
If you’re on a
recent-enough Perl (5.6 or later), you can use the
our
declaration to shorten it to:
package Cow; our @ISA = qw(Animal);
However, if you think your code might be used by people stuck with
Perl 5.005 or earlier, it’s be best to avoid
our
.
If you’re bringing in the class from outside, via an object-oriented module, change:
package Cow; use Animal; use vars qw(@ISA); @ISA = qw(Animal);
to just:
package Cow; use base qw(Animal);
That’s
pretty darn compact. Furthermore, use base
has the
advantage that it’s performed at compile time,
eliminating a few potential errors from setting
@ISA
at runtime, like some of the other solutions.
Let’s add a mouse that can barely be heard:
{ package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } } { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; print "[but you can barely hear it!]\n"; } } Mouse->speak;
which results in:
a Mouse goes squeak! [but you can barely hear it!]
Here, Mouse
has its own speaking routine, so
Mouse->speak
doesn’t
immediately invoke Animal->speak
. This is known
as overriding. You use overriding to shadow
the method in the derived class (Mouse
) because
you have a specialized version of the routine, instead of calling the
more general base class’s method (in
Animal
). In fact, you didn’t even
need to initialize @Mouse::ISA
to say that a
Mouse
was an Animal
at all
because all the methods needed for speak
are
defined completely with Mouse
.
You’ve
now duplicated some of the code from
Animal->speak
; this can be a maintenance
headache. For example, suppose someone decides that the word
goes
in the output of the
Animal
class is a bug. Now the maintainer of that
class changes goes
to says
.
Your mice will still say goes
, which means the
code still has the bug. The problem is that you invoked cut and paste
to duplicate code, and in OOP, that is a sin. You should reuse code
through inheritance, not by cut and paste.
How can you avoid that? Can you say somehow that a
Mouse
does everything any other
Animal
does, but add in the extra comment? Sure!
As your first attempt, you can invoke the
Animal::speak
method directly:
{ package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } } { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; Animal::speak($class); print "[but you can barely hear it!]\n"; } }
Note that because you’ve stopped using the method
arrow, you have to include the $class
parameter
(almost surely the value of "Mouse
“) as the first
parameter to Animal::speak
,.
Why did you stop using the arrow? Well, if you invoke
Animal->speak
there, the first parameter to the
method is "Animal,
" not
"Mouse
“, and when the time comes for it to call
for the sound
, it won’t have the
right class to select the proper methods for this object.
Invoking Animal::speak
directly is a mess,
however. What if Animal::speak
didn’t exist before and was inherited from a class
mentioned in @Animal::ISA
? For example, suppose
the code was:
{ package LivingCreature; sub speak { ... } ... } { package Animal; @ISA = qw(LivingCreature); # no definition for speak( ) ... } { package Mouse; @ISA = qw(Animal); sub speak { ... Animal::speak( ... ); } ... }
Because you no longer use the method arrow, you get one and only one
chance to hit the right subroutine. You’ll look for
it in Animal
, and not find it, and the program
aborts.
The Animal
classname is now hardwired into the
subroutine selection. This is a mess if someone maintains the code,
changing @ISA
for Mouse
, and
didn’t notice Animal
there in
speak
. Thus, this is probably not the right way to
go.
A better solution is to tell Perl to search from a different place in the inheritance chain:
{ package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } } { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; $class->Animal::speak(@_); print "[but you can barely hear it!]\n"; } }
Ahh. As ugly as this is, it works. Using this syntax, start with
Animal
to find speak
and use
all of Animal
’s inheritance chain
if not found immediately. The first parameter is
$class
(because you’re using an
arrow again), so the found speak
method gets
Mouse
as its first entry and eventually works its
way back to Mouse::sound
for the details.
This isn’t the best solution, however. You still
have to keep the @ISA
and the initial search
package in sync (changes in one must be considered for changes in the
other). Worse, if Mouse
had multiple entries in
@ISA
, you wouldn’t necessarily
know which one had actually defined speak
.
So, is there an even better way?
By changing the
Animal
class to the SUPER
class
in that invocation, you get a search of all your superclasses
(classes listed in @ISA
) automatically:
{ package Animal; sub speak { my $class = shift; print "a $class goes ", $class->sound, "!\n"; } } { package Mouse; @ISA = qw(Animal); sub sound { "squeak" } sub speak { my $class = shift; $class->SUPER::speak; print "[but you can barely hear it!]\n"; } }
Thus, SUPER::speak
means to look in the current
package’s @ISA
for
speak
, invoking the first one found if
there’s more than one. In this case, you look in the
one and only base class, Animal
, find
Animal::speak
, and pass it
"Mouse
" as its only parameter.
In
that last example, had there been any additional parameters to the
speak
routine (like how many times, or in what
pitch for singing, for example), the parameters would be ignored by
the Mouse::speak
routine. If you want them to be
passed uninterpreted to the parent class, you can add it as a
parameter:
$class->SUPER::speak(@_);
This invokes the speak
routine of the parent
class, including all the parameters that you’ve not
yet shifted off of your parameter
list.
Which one is correct? It depends. If you are writing a class that simply adds to some of the parent class behavior, it’s best to simply pass along arguments you haven’t dealt with. However, if you want precise control over the parent class behavior, you should determine the argument list explicitly, and pass it.
So far, you’ve seen the method arrow syntax:
Class->method(@args);
or the equivalent:
my $beast = "Class"; $beast->method(@args);
which constructs an argument list of:
("Class", @args)
and attempts to invoke:
Class::method("Class", @args);
However, if Class::method
is not found,
@Class::ISA
is examined (recursively) to locate a
package that does indeed contain method
, and that
subroutine is invoked instead.
Chapter 9 shows how to distinguish the individual animals by giving them associated properties, called instance variables.
The answers for all exercises can be found in Section A.7.
Type in the Animal
, Cow
,
Horse
, Sheep
, and
Mouse
class definitions. Make it work with
use strict
. Use our
if
you’re using a recent enough version of Perl. Your
program should ask the user to enter the names of one or more
barnyard animals. Create a barnyard with those animals, and have each
animal speak once.
Add a Person
class at the same level as
Animal
, and have both of them inherit from a new
class called LivingCreature
. Also make the
speak
method take a parameter of what to say,
falling back to the sound (humming for a Person
)
if no parameter is given. Since this isn’t Dr.
Doolittle, make sure the animals can’t talk. (That
is, don’t let speak
have any
parameters for an animal.) Try not to duplicate any code, but be sure
to catch likely errors of usage, such as forgetting to define a
sound
for an animal.
Demonstrate the Person
class by invoking a person
with nothing to say, and then demonstrate it a second time by
invoking a person with something to say.
[34] Although all examples in this book should
be valid Perl code, some examples in this chapter will break the
rules enforced by use strict
to make them easier
to understand. By the end of the chapter, though,
you’ll learn how to make
strict
-compliant code again.
[35] ISA is actually a linguistic term. Once again, Larry Wall’s background as a linguist has come back to influence Perl.
[36] The search is recursive,
depth-first and left to right in each @ISA
.