
Effective Perl Programming:
| ||||||||||||||||||||||||||||||||||||||||
| package Person; | # make Person the default package |
| $obj = { 'first' => 'Joseph', 'last' => 'Hall' }; | |
| # $obj is a hash reference | |
| bless $obj; | # bless $obj into Person |
| print "The person is $obj->{'first'} $obj->{'last'}\n"; | |
| # prints The person is Joseph Hall | |
Perl's object-typing mechanism is a runtime one. When creating an object, you must always explicitly bless it. The blessing operation generally occurs in a constructor, in combination with the process of creating the data in the object itself. A constructor is a subroutine, generally (but once again, not necessarily) called new, that is responsible for creating and blessing objects. Note that the constructor in the following example expects that the first argument passed into it will be the name of the class for which the constructor is written:
| package Person; | ||
| sub new { | # constructor for class Person | |
| my $class = shift; | # should be the string 'Person' | |
| my $self = { @_ }; | # make hash ref out of rest of args | |
| bless $self, $class; | # blesses $self into Person and returns it | |
| } | ||
I've used the two-argument form of bless, where I explicitly specify the class that the object will be blessed into. This will come in handy when I get around to discussing inheritance. You could call this constructor like this:
# this is the "ordinary subroutine call" syntax -- see below
my $joe = Person::new('Person', 'first' => 'Joseph', 'last' =>
'Hall');
I say you could, not should, because I haven't shown you the proper syntax for calling a constructor in Perl. That's a method call syntax, and that's coming up next.
Calling Methods in Perl
Perl methods are just ordinary Perl subroutines written to certain conventions. There are two types of methods: class methods and object methods.
A class method can be called with one of two different types of "method call syntax." The first is the so-called "indirect object" syntax, where the name of the method is followed by the class name, then the remaining arguments to the method. No comma follows the class name. Here's how we could call the Person constructor from above using indirect object syntax:
$joe = new Person 'first' => 'Joseph', 'last' => 'Hall';
Or, if you prefer:
$joe = new Person('first' => 'Joseph', 'last' => 'Hall');
Perl automatically translates this indirect object method call into the ordinary subroutine call syntax shown above it calls the subroutine new in the package Person and prepends the string 'Person' to the argument list. The second type of method call syntax is the "arrow syntax":
$joe = Person->new('first' => 'Joseph', 'last' => 'Hall');
This is equivalent to the indirect object form and is translated into an ordinary subroutine call in the same manner.
Object methods are similar to class methods, except that they take an object instead of a class name. I'll first define an object method for person:
| package Person; | # default package is Person | |
| sub first { | ||
| my $self = shift; | # first argument is object | |
| $self->{'first'}; | # return first name from a Person object | |
| } | ||
Assuming that $joe is still defined from one of the constructor calls above, we can invoke the method first with arrow syntax:
print "Joseph's first name is: ", $joe->first(), "\n";
Now, instead of supplying the class name as the first argument to the method, Perl supplies an object (in this case, $joe). And how does Perl know what class the method first is in? Simple $joe has been blessed into the class Person, so Perl looks there.
Although it's possible to do so, I don't recommend using indirect object syntax for object method calls. Stick to the arrow syntax for object methods the indirect object syntax has many potential pitfalls. You've been warned!
Inheritance in Perl
Method call syntax doesn't exist just for its eye appeal. If you call a nonexistent method, Perl will search an inheritance tree for other classes that might have a method by that name. For each class, the special array @ISA (pronounced "is a") contains a list of class names to search for inherited methods. Another way of looking at this is that for each class, @ISA is a list of that class's parent classes.
For example, assuming I'm still in the same file with the Person constructor above, suppose I have
package Programmer;
@ISA = qw(Person);
$john = new Programmer('first' => 'John', 'last' => 'Doe',
'language' => 'Perl');
Now, even if this is all I have for the class Programmer so far, it will, amazingly enough, work. Because there is no subroutine Programmer::new, Perl will search the Programmer inheritance tree for other classes that define new, and Perl will come up with Person::new, and call it like this:
$john = Person::new('Programmer', 'first' => 'John',
'last', => 'Doe', 'language' => 'Perl');
This is very important: the first argument Perl passes to Person::new is now 'Programmer', not 'Person', because new was called for class Programmer. The constructor I wrote for Person is inheritable because I used the two-argument form of bless. If I had used the one-argument form, $john would have been blessed into Person, which would be wrong. I can even make this "generic, inheritable constructor" a little more succinct (this is a pretty handy snippet of code, actually):
package Person;
sub new { # the generic, inheritable constructor
my $class = shift;
bless { @_ }, $class; # combine anon hash and blessing
}
Thoughts on Object-Oriented Perl
There are many reasons why object-oriented programming in Perl is a much less complicated affair than it is in a language like C++. For one, Perl has built-in memory management. C++ constructors often devote a lot of code to memory allocation issues. Such code is extremely rare in Perl.
Another reason is that Perl does not support data inheritance. In Perl, only methods are inherited. This may seem curious at first, but it makes sense because Perl lacks rigid structured types like C's structs. Also along those lines, Perl lacks extensive "access control" features like the public, private, and protected members of C++ classes. Not having to make, and later modify, decisions about member access definitely helps simplify the process of prototyping object-oriented applications and modules in Perl.
In my next column, I'll discuss some ways in which you can implement some of the object-oriented programming features that Perl is apparently lacking for example, private class data. I'll also show you a real-world example of subclassing and using an existing object-oriented module from the CPAN (Comprehensive Perl Archive Network).
|
7th August 1998 efc Last changed: 7th August 1998 efc |
|