=head1 NAME
-perltoot - tchrist's object-oriented perl tutorial (rev 0.4)
+perltoot - Tom's object-oriented tutorial for perl
=head1 DESCRIPTION
Asking an object to do something for you is calling an I<object method>.
Asking either a class (usually) or an object (sometimes) to give you
back an object is calling a I<constructor>, which is just a
-particular kind of method.
+kind of method.
That's all well and good, but how is an object different from any other
Perl data type? Just what is an object I<really>; that is, what's its
While a constructor may be named anything you'd like, most Perl
programmers seem to like to call theirs new(). However, new() is not
a reserved word, and a class is under no obligation to supply such.
-Some programmers have also been known to use a function with
+Some programmers have also been known to use a function with
the same name as the class as the constructor.
=head2 Object Representation
By far the most common mechanism used in Perl to represent a Pascal
record, a C struct, or a C++ class an anonymous hash. That's because a
hash has an arbitrary number of data fields, each conveniently accessed by
-an arbitrary name of your own devising.
+an arbitrary name of your own devising.
If you were just doing a simple
struct-like emulation, you would likely go about it something like this:
with an even one instead, you can't expect the compiler to catch this.
(Well, you can expect it all you like, but it's not going to happen.)
-Let's suppose you have a well-educated user of you Person class,
+Let's suppose you have a well-educated user of your Person class,
someone who has read the docs that explain the prescribed
interface. Here's how they might use the Person class:
the best we can do right now. Nonetheless, rest assured that when your
program is finished, its objects' destructors are all duly called.
So you are guaranteed that an object I<eventually> gets properly
-destructed, except in the unique case of a program that never exits.
+destroyed, except in the unique case of a program that never exits.
(If you're running Perl embedded in another application, this full GC
pass happens a bit more frequently--whenever a thread shuts down.)
There's no reason to limit methods to those that simply access data.
Methods can do anything at all. The key point is that they're invoked
against an object or a class. Let's say we'd like object methods that
-do more than fetch or set one particular field .
+do more than fetch or set one particular field.
sub exclaim {
my $self = shift;
to remind ourselves that this field is special and not to be used as
a public data member in the same way that NAME, AGE, and PEERS are.
(Because we've been developing this code under the strict pragma, prior
-to 5.004 we'll have to quote the field name.)
+to perl version 5.004 we'll have to quote the field name.)
sub new {
my $proto = shift;
-- ${ $self->{"_CENSUS"} };
}
+What happens if a derived class (which we'll all C<Employee>) inherits
+methods from this person one? Then C<Employee->debug()> when called
+as a class method manipulates $Person::Debugging not $Employee::Debugging.
+
=head2 Class Destructors
-The object destructor handles for each particular object. But sometimes
+The object destructor handles the death of each distinct object. But sometimes
you want a bit of cleanup when the entire class is shut down, which
currently only happens when the program exits. To make such a
I<class destructor>, create a function in that class's package named
methods access package data via that reference, so we should be ok.
What do we mean by the Person::new() function -- isn't that actually
-method. Well, in principle, yes. A method is just a function that
+a method? Well, in principle, yes. A method is just a function that
expects as its first argument a class name (package) or object
-(bless reference). Person::new() is the function that both the
+(blessed reference). Person::new() is the function that both the
C<Person-E<gt>new()> method and the C<Employee-E<gt>new()> method end
up calling. Understand that while a method call looks a lot like a
function call, they aren't really quite the same, and if you treat them
So don't use function calls when you mean to call a method.
If an employee is just a Person, that's not all too very interesting.
-So let's add some other methods. We'll give our employee
+So let's add some other methods. We'll give our employee
data fields to access their salary, their employee ID, and their
start date.
}
There, we've just demonstrated the high-falutin' concept known in certain
-circles as I<polymorphism>. We've taken on the form and behavior of
+circles as I<polymorphism>. We've taken on the form and behaviour of
an existing object, and then we've altered it to suit our own purposes.
This is a form of Laziness. (Getting polymorphed is also what happens
when the wizard decides you'd look better as a frog.)
you inherit from, or add others. Fortunately, the pseudoclass SUPER
comes to the rescue here.
- $class->SUPER::debug($Debugging);
+ $self->SUPER::debug($Debugging);
This way it starts looking in my class's @ISA. This only makes sense
from I<within> a method call, though. Don't try to access anything
printf "His peers are: %s\n", join(", ", $boss->peers);
Running it, we see that we're still ok. If you'd like to dump out your
-object in a nice format, the way the 'x' command does in the debugger,
-you could use these undocumented calls the debugger employs (until
-its author changes them).
+object in a nice format, somewhat like the way the 'x' command works in
+the debugger, you could use the Data::Dumper module from CPAN this way:
- require 'dumpvar.pl';
+ use Data::Dumper;
print "Here's the boss:\n";
- dumpValue($boss);
+ print Dumper($boss);
Which shows us something like this:
- Boss=HASH(0x8104084)
- '_CENSUS' => SCALAR(0x80c949c)
- -> 1
- 'AGE' => 47
- 'FULLNAME' => Fullname=HASH(0x81040d8)
- 'CHRISTIAN' => 'Federico Miguel'
- 'NICK' => 'Fred'
- 'SURNAME' => 'Pichon Alvarez'
- 'TITLE' => 'Don'
- 'PEERS' => ARRAY(0x80ebb3c)
- 0 'Frank'
- 1 'Felipe'
- 2 'Faust'
+ Here's the boss:
+ $VAR1 = bless( {
+ _CENSUS => \1,
+ FULLNAME => bless( {
+ TITLE => 'Don',
+ SURNAME => 'Pichon Alvarez',
+ NICK => 'Fred',
+ CHRISTIAN => 'Federico Jesus'
+ }, 'Fullname' ),
+ AGE => 47,
+ PEERS => [
+ 'Frank',
+ 'Felipe',
+ 'Faust'
+ ]
+ }, 'Boss' );
Hm.... something's missing there. What about the salary, start date,
and ID fields? Well, we never set them to anything, even undef, so they
However, there is one particular area where MI in Perl is rampant:
borrowing another class's class methods. This is rather common,
-particularly with some bundled "objectless" classes,
+especially with some bundled "objectless" classes,
like Exporter, DynaLoader, AutoLoader, and SelfLoader. These classes
do not provide constructors; they exist only so you may inherit their
-class methods. (It's not entirey clear why inheritance was done
+class methods. (It's not entirely clear why inheritance was done
here rather than traditional module importation.)
For example, here is the POSIX module's @ISA:
Why don't people use MI for object methods much? One reason is that
it can have complicated side-effects. For one thing, your inheritance
graph (no longer a tree) might converge back to the same base class.
-Although Perl guards against recursive inheritance, but having parents
+Although Perl guards against recursive inheritance, merely having parents
who are related to each other via a common ancestor, incestuous though
it sounds, is not forbidden. What if in our Third class shown above we
wanted its new() method to also call both overridden constructors in its
having to go and add it to each and every @ISA. Well, it turns out that
you can. You don't see it, but Perl tacitly and irrevocably assumes
that there's an extra element at the end of @ISA: the class UNIVERSAL.
-In 5.003, there were no predefined methods there, but you could put
+In version 5.003, there were no predefined methods there, but you could put
whatever you felt like into it.
-However, as of 5.004 (or some subversive releases, like 5.003_08),
+However, as of version 5.004 (or some subversive releases, like 5.003_08),
UNIVERSAL has some methods in it already. These are built-in to your Perl
binary, so they don't take any extra time to load. Predefined methods
include isa(), can(), and VERSION(). isa() tells you whether an object or
A bigger difference between the two approaches can be found in memory use.
A hash representation takes up more memory than an array representation
because you have to allocation memory for the keys as well as the values.
-However, it really isn't that bad, especially since as of 5.004,
-memory is only allocated one for a given hash key, no matter how many
+However, it really isn't that bad, especially since as of version 5.004,
+memory is only allocated once for a given hash key, no matter how many
hashes have that key. It's expected that sometime in the future, even
these differences will fade into obscurity as more efficient underlying
representations are devised.
put the data into an anonymous hash that's lexically visible only to
the closure we create, bless, and return as the object. This object's
methods turn around and call the closure as a regular subroutine call,
-passing it as a particular argument the field we want to affect. (Yes,
+passing it the field we want to affect. (Yes,
the double-function call is slow, but if you wanted fast, you wouldn't
be using objects at all, eh? :-)
Because this object is hidden behind a code reference, it's probably a bit
mysterious to those whose background is more firmly rooted in standard
procedural or object-based programming languages than in functional
-procedural programming languages whence closures derive. The object
+programming languages whence closures derive. The object
created and returned by the new() method is itself not a data reference
as we've seen before. It's an anonymous code reference that has within
-it access to a particular version (lexical binding and instantiation)
+it access to a specific version (lexical binding and instantiation)
of the object's data, which are stored in the private variable $self.
Although this is the same function each time, it contains a different
version of $self.
-When a method like C<$him-E<gt>name("Jason") is called, its implicit
-zeroth argument is as the invoking object just as it is with all method
+When a method like C<$him-E<gt>name("Jason")> is called, its implicit
+zeroth argument is the invoking object just as it is with all method
calls. But in this case, it's our code reference (something like a
function pointer in C++, but with deep binding of lexical variables).
There's not a lot to be done with a code reference beyond calling it, so
requested service. When used in this way, you may think
of autoloaded methods as "proxy" methods.
-When Perl tries to call an undefined function is a particular package
+When Perl tries to call an undefined function in a particular package
and that function is not defined, it looks for a function in
that same package called AUTOLOAD. If one exists, it's called
with the same arguments as the original function would have had.
we'll use the autoload mechanism to generate (actually, mimic) methods on
the fly. To verify that we're accessing a valid member, we will check
against an C<_permitted> (pronounced "under-permitted") field, which
-is a reference to a file-static hash of permitted fields in this record
+is a reference to a file-scoped lexical (like a C file static) hash of permitted fields in this record
called %fields. Why the underscore? For the same reason as the _CENSUS
field we once used: as a marker that means "for internal use only".
Pretty nifty, eh? All we have to do to add new data fields
is modify %fields. No new functions need be written.
+I could have avoided the C<_permitted> field entirely, but I
+wanted to demonstrate how to store a reference to class data on the
+object so you wouldn't have to access that class data
+directly from an object method.
+
=head2 Inherited Autoloaded Data Methods
But what about inheritance? Can we define our Employee
we'll grab Person's version of that via inheritance,
and it will all work out just fine.
-=head1 Metaclass Tools
+=head1 Metaclassical Tools
Even though proxy methods can provide a more convenient approach to making
more struct-like classes than tediously coding up data methods as
Perl programmers have responded to this by creating several different
class construction classes. These metaclasses are classes
-that create other classes. Three worth looking at are
-Class::Template, Class::MethodMaker, and Alias. All can be
+that create other classes. A couple worth looking at are
+Class::Template and Alias. These and other related metaclasses can be
found in the modules directory on CPAN.
=head2 Class::Template
One of the older ones is Class::Template. In fact, its syntax and
interface were sketched out long before perl5 even solidified into a
real thing. What it does is provide you a way to "declare"
-a class as having objects whose fields are of a particular type.
+a class as having objects whose fields are of a specific type.
The function that does this is called, not surprisingly
enough, struct().
wanted to override Perl's idea of gethostbyname() and gethostbyaddr() so
that they would return objects that acted like C structures. We don't
care about high-falutin' OO gunk. All we want is for these objects to
-act like structs in the C sense.
+act like structs in the C sense.
use Socket;
use Net::hostent;
$h->name, inet_ntoa($h->addr);
Here's how to do this using the Class::Template module.
-They crux is going to be this call:
+The crux is going to be this call:
- struct 'Net::hostent' => [
+ struct 'Net::hostent' => [ # note bracket
name => '$',
aliases => '@',
addrtype => '$',
We could also have implemented our object this way:
- struct 'Net::hostent' => {
+ struct 'Net::hostent' => { # note brace
name => '$',
aliases => '@',
addrtype => '$',
type, instead of an anonymous array. The array is faster and smaller,
but the hash works out better if you eventually want to do inheritance.
Since for this struct-like object we aren't planning on inheritance,
-we'll go for better speed and size over better flexibility.
+this time we'll opt for better speed and size over better flexibility.
Here's the whole implementation:
User::grent, and User::pwent. These modules have a final component
that's all lower-case, by convention reserved for compiler pragmas,
because they affect the compilation and change a built-in function.
-They also have the type name that a C programmer would most expect.
+They also have the type names that a C programmer would most expect.
=head2 Data Members as Variables
For example, it's common to call an object an I<instance> of a class
and to call those objects' methods I<instance methods>. Data fields
-particular to each object are often called I<instance data> or <object
+peculiar to each object are often called I<instance data> or I<object
attributes>, and data fields common to all members of that class are
I<class data>, I<class attributes>, or I<static data members>.
-Also, I<base class>, I<generic class>, and I<subclass> all describe
+Also, I<base class>, I<generic class>, and I<superclass> all describe
the same notion, whereas I<derived class>, I<specific class>, and
-I<superclass> describe the other related one.
+I<subclass> describe the other related one.
C++ programmers have I<static methods> and I<virtual methods>,
-but Perl only has I<class methods> and I<object methods>.
+but Perl only has I<class methods> and I<object methods>.
Actually, Perl only has methods. Whether a method gets used
as a class or object method is by usage only. You could accidentally
-call a class method (one expecting a string argument) on an
+call a class method (one expecting a string argument) on an
object (one expecting a reference), or vice versa.
>From the C++ perspective, all methods in Perl are virtual.
Because a class is itself something of an object, Perl's classes can be
taken as describing both a "class as meta-object" (also called I<object
factory>) philosophy and the "class as type definition" (I<declaring>
-behavior, not I<defining> mechanism) idea. C++ supports the latter
+behaviour, not I<defining> mechanism) idea. C++ supports the latter
notion, but not the former.
-=head2 Programming with Style
-
-Remember the underscores we used on "start_date" and "START_DATE"?
-While some programmers might be tempted to leave them out, please don't.
-Otherwise it's hard for some people to read. Also, you'd have to make
-up a new rule for identifiers that you've rendered in all capitals,
-like START_DATE. Plus you get people wondering whether it's "startdate",
-"Startdate", "startDate", "StartDate", or some other crazy variation.
-And adding another word, like "employee_start_date", just racks up the
-confusion. Nobody but a compiler wants to parse "employeestartdate" or
-even "EmployeeStartDate". So (almost) always use underscores to separate
-words in identifiers. See also L<perlstyle> and either L<perlmod> or the
-list of registered modules posted periodically to comp.lang.perl.modules
-or found on CPAN in the http://www.perl.com/CPAN/modules/ directory.
-
=head1 SEE ALSO
The following man pages will doubtless provide more
=head2 Acknowledgments
-Thanks to Brad Appleton, Raphael Manfredi, Dean Roehrich, Gurusamy
-Sarathy, and many others from the perl porters list for their helpful
-comments.
+Thanks to
+Larry Wall,
+Roderick Schertler,
+Gurusamy Sarathy,
+Dean Roehrich,
+Raphael Manfredi,
+Brent Halsey,
+Greg Bacon,
+Brad Appleton,
+and many others for their helpful comments.