1N/Aperltoot - Tom's object-oriented tutorial for perl
1N/AObject-oriented programming is a big seller these days. Some managers
1N/Awould rather have objects than sliced bread. Why is that? What's so
1N/Aspecial about an object? Just what I<is> an object anyway?
1N/AAn object is nothing but a way of tucking away complex behaviours into
1N/Aa neat little easy-to-use bundle. (This is what professors call
1N/Aabstraction.) Smart people who have nothing to do but sit around for
1N/Aweeks on end figuring out really hard problems make these nifty
1N/Aobjects that even regular people can use. (This is what professors call
1N/Asoftware reuse.) Users (well, programmers) can play with this little
1N/Abundle all they want, but they aren't to open it up and mess with the
1N/Ainsides. Just like an expensive piece of hardware, the contract says
1N/Athat you void the warranty if you muck with the cover. So don't do that.
1N/AThe heart of objects is the class, a protected little private namespace
1N/Afull of data and functions. A class is a set of related routines that
1N/Aaddresses some problem area. You can think of it as a user-defined type.
1N/AThe Perl package mechanism, also used for more traditional modules,
1N/Ais used for class modules as well. Objects "live" in a class, meaning
1N/Athat they belong to some package.
1N/AMore often than not, the class provides the user with little bundles.
1N/AThese bundles are objects. They know whose class they belong to,
1N/Aand how to behave. Users ask the class to do something, like "give
1N/Ame an object." Or they can ask one of these objects to do something.
1N/AAsking a class to do something for you is calling a I<class method>.
1N/AAsking an object to do something for you is calling an I<object method>.
1N/AAsking either a class (usually) or an object (sometimes) to give you
1N/Aback an object is calling a I<constructor>, which is just a
1N/AThat's all well and good, but how is an object different from any other
1N/APerl data type? Just what is an object I<really>; that is, what's its
1N/Afundamental type? The answer to the first question is easy. An object
1N/Ais different from any other data type in Perl in one and only one way:
1N/Ayou may dereference it using not merely string or numeric subscripts
1N/Aas with simple arrays and hashes, but with named subroutine calls.
1N/AIn a word, with I<methods>.
1N/AThe answer to the second question is that it's a reference, and not just
1N/Aany reference, mind you, but one whose referent has been I<bless>()ed
1N/Ainto a particular class (read: package). What kind of reference? Well,
1N/Athe answer to that one is a bit less concrete. That's because in Perl
1N/Athe designer of the class can employ any sort of reference they'd like
1N/Aas the underlying intrinsic data type. It could be a scalar, an array,
1N/Aor a hash reference. It could even be a code reference. But because
1N/Aof its inherent flexibility, an object is usually a hash reference.
1N/A=head1 Creating a Class
1N/ABefore you create a class, you need to decide what to name it. That's
1N/Abecause the class (package) name governs the name of the file used to
1N/Ahouse it, just as with regular modules. Then, that class (package)
1N/Ashould provide one or more ways to generate objects. Finally, it should
1N/Aprovide mechanisms to allow users of its objects to indirectly manipulate
1N/Athese objects from a distance.
1N/AFor example, let's make a simple Person class module. It gets stored in
1N/Athe file
Person.pm. If it were called a Happy::Person class, it would
1N/AHappy::Person instead of just Person. (On a personal computer not
1N/Arunning Unix or Plan 9, but something like Mac OS or VMS, the directory
1N/Aseparator may be different, but the principle is the same.) Do not assume
1N/Aany formal relationship between modules based on their directory names.
1N/AThis is merely a grouping convenience, and has no effect on inheritance,
1N/Avariable accessibility, or anything else.
1N/AFor this module we aren't going to use Exporter, because we're
1N/Aa well-behaved class module that doesn't export anything at all.
1N/AIn order to manufacture objects, a class needs to have a I<constructor
1N/Amethod>. A constructor gives you back not just a regular data type,
1N/Abut a brand-new object in that class. This magic is taken care of by
1N/Athe bless() function, whose sole purpose is to enable its referent to
1N/Abe used as an object. Remember: being an object really means nothing
1N/Amore than that methods may now be called against it.
1N/AWhile a constructor may be named anything you'd like, most Perl
1N/Aprogrammers seem to like to call theirs new(). However, new() is not
1N/Aa reserved word, and a class is under no obligation to supply such.
1N/ASome programmers have also been known to use a function with
1N/Athe same name as the class as the constructor.
1N/A=head2 Object Representation
1N/ABy far the most common mechanism used in Perl to represent a Pascal
1N/Arecord, a C struct, or a C++ class is an anonymous hash. That's because a
1N/Ahash has an arbitrary number of data fields, each conveniently accessed by
1N/Aan arbitrary name of your own devising.
1N/AIf you were just doing a simple
1N/Astruct-like emulation, you would likely go about it something like this:
1N/A peers => [ "Norbert", "Rhys", "Phineas"],
1N/AIf you felt like it, you could add a bit of visual distinction
1N/Aby up-casing the hash keys:
1N/A PEERS => [ "Norbert", "Rhys", "Phineas"],
1N/AAnd so you could get at C<< $rec->{NAME} >> to find "Jason", or
1N/AC<< @{ $rec->{PEERS} } >> to get at "Norbert", "Rhys", and "Phineas".
1N/A(Have you ever noticed how many 23-year-old programmers seem to
1N/Abe named "Jason" these days? :-)
1N/AThis same model is often used for classes, although it is not considered
1N/Athe pinnacle of programming propriety for folks from outside the
1N/Aclass to come waltzing into an object, brazenly accessing its data
1N/Amembers directly. Generally speaking, an object should be considered
1N/Aan opaque cookie that you use I<object methods> to access. Visually,
1N/Amethods look like you're dereffing a reference using a function name
1N/Ainstead of brackets or braces.
1N/A=head2 Class Interface
1N/ASome languages provide a formal syntactic interface to a class's methods,
1N/Abut Perl does not. It relies on you to read the documentation of each
1N/Aclass. If you try to call an undefined method on an object, Perl won't
1N/Acomplain, but the program will trigger an exception while it's running.
1N/ALikewise, if you call a method expecting a prime number as its argument
1N/Awith a non-prime one instead, you can't expect the compiler to catch this.
1N/A(Well, you can expect it all you like, but it's not going to happen.)
1N/ALet's suppose you have a well-educated user of your Person class,
1N/Asomeone who has read the docs that explain the prescribed
1N/Ainterface. Here's how they might use the Person class:
1N/A $him = Person->new();
1N/A $him->name("Jason");
1N/A $him->peers( "Norbert", "Rhys", "Phineas" );
1N/A push @All_Recs, $him; # save object in array for later
1N/A printf "%s is %d years old.\n", $him->name, $him->age;
1N/A print "His peers are: ", join(", ", $him->peers), "\n";
1N/A printf "Last rec's name is %s\n", $All_Recs[-1]->name;
1N/AAs you can see, the user of the class doesn't know (or at least, has no
1N/Abusiness paying attention to the fact) that the object has one particular
1N/Aimplementation or another. The interface to the class and its objects
1N/Ais exclusively via methods, and that's all the user of the class should
1N/A=head2 Constructors and Instance Methods
1N/AStill, I<someone> has to know what's in the object. And that someone is
1N/Athe class. It implements methods that the programmer uses to access
1N/Athe object. Here's how to implement the Person class using the standard
1N/Ahash-ref-as-an-object idiom. We'll make a class method called new() to
1N/Aact as the constructor, and three object methods called name(), age(), and
1N/Apeers() to get at per-object data hidden away in our anonymous hash.
1N/A ##################################################
1N/A ## the object constructor (simplistic version) ##
1N/A ##################################################
1N/A $self->{NAME} = undef;
1N/A $self->{AGE} = undef;
1N/A $self->{PEERS} = [];
1N/A bless($self); # but see below
1N/A ##############################################
1N/A ## methods to access per-object data ##
1N/A ## With args, they set the value. Without ##
1N/A ##############################################
1N/A if (@_) { $self->{NAME} = shift }
1N/A return $self->{NAME};
1N/A if (@_) { $self->{AGE} = shift }
1N/A return $self->{AGE};
1N/A if (@_) { @{ $self->{PEERS} } = @_ }
1N/A return @{ $self->{PEERS} };
1N/A 1; # so the require or use succeeds
1N/AWe've created three methods to access an object's data, name(), age(),
1N/Aand peers(). These are all substantially similar. If called with an
1N/Aargument, they set the appropriate field; otherwise they return the
1N/Avalue held by that field, meaning the value of that hash key.
1N/A=head2 Planning for the Future: Better Constructors
1N/AEven though at this point you may not even know what it means, someday
1N/Ayou're going to worry about inheritance. (You can safely ignore this
1N/Afor now and worry about it later if you'd like.) To ensure that this
1N/Aall works out smoothly, you must use the double-argument form of bless().
1N/AThe second argument is the class into which the referent will be blessed.
1N/ABy not assuming our own class as the default second argument and instead
1N/Ausing the class passed into us, we make our constructor inheritable.
1N/A $self->{NAME} = undef;
1N/A $self->{AGE} = undef;
1N/A $self->{PEERS} = [];
1N/A bless ($self, $class);
1N/AThat's about all there is for constructors. These methods bring objects
1N/Ato life, returning neat little opaque bundles to the user to be used in
1N/Asubsequent method calls.
1N/AEvery story has a beginning and an end. The beginning of the object's
1N/Astory is its constructor, explicitly called when the object comes into
1N/Aexistence. But the ending of its story is the I<destructor>, a method
1N/Aimplicitly called when an object leaves this life. Any per-object
1N/Aclean-up code is placed in the destructor, which must (in Perl) be called
1N/AIf constructors can have arbitrary names, then why not destructors?
1N/ABecause while a constructor is explicitly called, a destructor is not.
1N/ADestruction happens automatically via Perl's garbage collection (GC)
1N/Asystem, which is a quick but somewhat lazy reference-based GC system.
1N/ATo know what to call, Perl insists that the destructor be named DESTROY.
1N/APerl's notion of the right time to call a destructor is not well-defined
1N/Acurrently, which is why your destructors should not rely on when they are
1N/AWhy is DESTROY in all caps? Perl on occasion uses purely uppercase
1N/Afunction names as a convention to indicate that the function will
1N/Abe automatically called by Perl in some way. Others that are called
1N/Aimplicitly include BEGIN, END, AUTOLOAD, plus all methods used by
1N/Atied objects, described in L<perltie>.
1N/AIn really good object-oriented programming languages, the user doesn't
1N/Acare when the destructor is called. It just happens when it's supposed
1N/Ato. In low-level languages without any GC at all, there's no way to
1N/Adepend on this happening at the right time, so the programmer must
1N/Aexplicitly call the destructor to clean up memory and state, crossing
1N/Atheir fingers that it's the right time to do so. Unlike C++, an
1N/Aobject destructor is nearly never needed in Perl, and even when it is,
1N/Aexplicit invocation is uncalled for. In the case of our Person class,
1N/Awe don't need a destructor because Perl takes care of simple matters
1N/Alike memory deallocation.
1N/AThe only situation where Perl's reference-based GC won't work is
1N/Awhen there's a circularity in the data structure, such as:
1N/A $this->{WHATEVER} = $this;
1N/AIn that case, you must delete the self-reference manually if you expect
1N/Ayour program not to leak memory. While admittedly error-prone, this is
1N/Athe best we can do right now. Nonetheless, rest assured that when your
1N/Aprogram is finished, its objects' destructors are all duly called.
1N/ASo you are guaranteed that an object I<eventually> gets properly
1N/Adestroyed, except in the unique case of a program that never exits.
1N/A(If you're running Perl embedded in another application, this full GC
1N/Apass happens a bit more frequently--whenever a thread shuts down.)
1N/A=head2 Other Object Methods
1N/AThe methods we've talked about so far have either been constructors or
1N/Aelse simple "data methods", interfaces to data stored in the object.
1N/AThese are a bit like an object's data members in the C++ world, except
1N/Athat strangers don't access them as data. Instead, they should only
1N/Aaccess the object's data indirectly via its methods. This is an
1N/Aimportant rule: in Perl, access to an object's data should I<only>
1N/Abe made through methods.
1N/APerl doesn't impose restrictions on who gets to use which methods.
1N/AThe public-versus-private distinction is by convention, not syntax.
1N/A(Well, unless you use the Alias module described below in
1N/AL<Data Members as Variables>.) Occasionally you'll see method names beginning or ending
1N/Awith an underscore or two. This marking is a convention indicating
1N/Athat the methods are private to that class alone and sometimes to its
1N/Aclosest acquaintances, its immediate subclasses. But this distinction
1N/Ais not enforced by Perl itself. It's up to the programmer to behave.
1N/AThere's no reason to limit methods to those that simply access data.
1N/AMethods can do anything at all. The key point is that they're invoked
1N/Aagainst an object or a class. Let's say we'd like object methods that
1N/Ado more than fetch or set one particular field.
1N/A return sprintf "Hi, I'm %s, age %d, working with %s",
1N/A $self->{NAME}, $self->{AGE}, join(", ", @{$self->{PEERS}});
1N/AOr maybe even one like this:
1N/A sub happy_birthday {
1N/A return ++$self->{AGE};
1N/ASome might argue that one should go at these this way:
1N/A return sprintf "Hi, I'm %s, age %d, working with %s",
1N/A $self->name, $self->age, join(", ", $self->peers);
1N/A sub happy_birthday {
1N/A return $self->age( $self->age() + 1 );
1N/ABut since these methods are all executing in the class itself, this
1N/Amay not be critical. There are tradeoffs to be made. Using direct
1N/Ahash access is faster (about an order of magnitude faster, in fact), and
1N/Ait's more convenient when you want to interpolate in strings. But using
1N/Amethods (the external interface) internally shields not just the users of
1N/Ayour class but even you yourself from changes in your data representation.
1N/AWhat about "class data", data items common to each object in a class?
1N/AWhat would you want that for? Well, in your Person class, you might
1N/Alike to keep track of the total people alive. How do you implement that?
1N/AYou I<could> make it a global variable called $Person::Census. But about
1N/Aonly reason you'd do that would be if you I<wanted> people to be able to
1N/Aget at your class data directly. They could just say $Person::Census
1N/Aand play around with it. Maybe this is ok in your design scheme.
1N/AYou might even conceivably want to make it an exported variable. To be
1N/Aexportable, a variable must be a (package) global. If this were a
1N/Atraditional module rather than an object-oriented one, you might do that.
1N/AWhile this approach is expected in most traditional modules, it's
1N/Agenerally considered rather poor form in most object modules. In an
1N/Aobject module, you should set up a protective veil to separate interface
1N/Afrom implementation. So provide a class method to access class data
1N/Ajust as you provide object methods to access object data.
1N/ASo, you I<could> still keep $Census as a package global and rely upon
1N/Aothers to honor the contract of the module and therefore not play around
1N/Awith its implementation. You could even be supertricky and make $Census a
1N/Atied object as described in L<perltie>, thereby intercepting all accesses.
1N/ABut more often than not, you just want to make your class data a
1N/Afile-scoped lexical. To do so, simply put this at the top of the file:
1N/AEven though the scope of a my() normally expires when the block in which
1N/Ait was declared is done (in this case the whole file being required or
1N/Aused), Perl's deep binding of lexical variables guarantees that the
1N/Avariable will not be deallocated, remaining accessible to functions
1N/Adeclared within that scope. This doesn't work with global variables
1N/Agiven temporary values via local(), though.
1N/AIrrespective of whether you leave $Census a package global or make
1N/Ait instead a file-scoped lexical, you should make these
1N/Achanges to your Person::new() constructor:
1N/A $self->{NAME} = undef;
1N/A $self->{AGE} = undef;
1N/A $self->{PEERS} = [];
1N/A bless ($self, $class);
1N/ANow that we've done this, we certainly do need a destructor so that
1N/Awhen Person is destroyed, the $Census goes down. Here's how
1N/A sub DESTROY { --$Census }
1N/ANotice how there's no memory to deallocate in the destructor? That's
1N/Asomething that Perl takes care of for you all by itself.
1N/AAlternatively, you could use the Class::Data::Inheritable module from
1N/A=head2 Accessing Class Data
1N/AIt turns out that this is not really a good way to go about handling
1N/Aclass data. A good scalable rule is that I<you must never reference class
1N/Adata directly from an object method>. Otherwise you aren't building a
1N/Ascalable, inheritable class. The object must be the rendezvous point
1N/Afor all operations, especially from an object method. The globals
1N/A(class data) would in some sense be in the "wrong" package in your
1N/Aderived classes. In Perl, methods execute in the context of the class
1N/Athey were defined in, I<not> that of the object that triggered them.
1N/ATherefore, namespace visibility of package globals in methods is unrelated
1N/AGot that? Maybe not. Ok, let's say that some other class "borrowed"
1N/A(well, inherited) the DESTROY method as it was defined above. When those
1N/Aobjects are destroyed, the original $Census variable will be altered,
1N/Anot the one in the new class's package namespace. Perhaps this is what
1N/Ayou want, but probably it isn't.
1N/AHere's how to fix this. We'll store a reference to the data in the
1N/Avalue accessed by the hash key "_CENSUS". Why the underscore? Well,
1N/Amostly because an initial underscore already conveys strong feelings
1N/Aof magicalness to a C programmer. It's really just a mnemonic device
1N/Ato remind ourselves that this field is special and not to be used as
1N/Aa public data member in the same way that NAME, AGE, and PEERS are.
1N/A(Because we've been developing this code under the strict pragma, prior
1N/Ato perl version 5.004 we'll have to quote the field name.)
1N/A $self->{NAME} = undef;
1N/A $self->{AGE} = undef;
1N/A $self->{PEERS} = [];
1N/A $self->{"_CENSUS"} = \$Census;
1N/A bless ($self, $class);
1N/A ++ ${ $self->{"_CENSUS"} };
1N/A return ${ $self->{"_CENSUS"} };
1N/A -- ${ $self->{"_CENSUS"} };
1N/A=head2 Debugging Methods
1N/AIt's common for a class to have a debugging mechanism. For example,
1N/Ayou might want to see when objects are created or destroyed. To do that,
1N/Aadd a debugging variable as a file-scoped lexical. For this, we'll pull
1N/Ain the standard Carp module to emit our warnings and fatal messages.
1N/AThat way messages will come out with the caller's filename and
1N/Aline number instead of our own; if we wanted them to be from our own
1N/Aperspective, we'd just use die() and warn() directly instead of croak()
1N/Aand carp() respectively.
1N/ANow add a new class method to access the variable.
1N/A if (ref $class) { confess "Class method called as object method" }
1N/A unless (@_ == 1) { confess "usage: CLASSNAME->debug(level)" }
1N/ANow fix up DESTROY to murmur a bit as the moribund object expires:
1N/A if ($Debugging) { carp "Destroying $self " . $self->name }
1N/A -- ${ $self->{"_CENSUS"} };
1N/AOne could conceivably make a per-object debug state. That
1N/Away you could call both of these:
1N/A Person->debug(1); # entire class
1N/A $him->debug(1); # just this object
1N/ATo do so, we need our debugging method to be a "bimodal" one, one that
1N/Aworks on both classes I<and> objects. Therefore, adjust the debug()
1N/Aand DESTROY methods as follows:
1N/A confess "usage: thing->debug(level)" unless @_ == 1;
1N/A $self->{"_DEBUG"} = $level; # just myself
1N/A $Debugging = $level; # whole class
1N/A if ($Debugging || $self->{"_DEBUG"}) {
1N/A carp "Destroying $self " . $self->name;
1N/A -- ${ $self->{"_CENSUS"} };
1N/AWhat happens if a derived class (which we'll call Employee) inherits
1N/Amethods from this Person base class? Then C<< Employee->debug() >>, when called
1N/Aas a class method, manipulates $Person::Debugging not $Employee::Debugging.
1N/A=head2 Class Destructors
1N/AThe object destructor handles the death of each distinct object. But sometimes
1N/Ayou want a bit of cleanup when the entire class is shut down, which
1N/Acurrently only happens when the program exits. To make such a
1N/AI<class destructor>, create a function in that class's package named
1N/AEND. This works just like the END function in traditional modules,
1N/Ameaning that it gets called whenever your program exits unless it execs
1N/Aor dies of an uncaught signal. For example,
1N/A print "All persons are going away now.\n";
1N/AWhen the program exits, all the class destructors (END functions) are
1N/Abe called in the opposite order that they were loaded in (LIFO order).
1N/A=head2 Documenting the Interface
1N/AAnd there you have it: we've just shown you the I<implementation> of this
1N/APerson class. Its I<interface> would be its documentation. Usually this
1N/Ameans putting it in pod ("plain old documentation") format right there
1N/Ain the same file. In our Person example, we would place the following
1N/Adocs anywhere in the
Person.pm file. Even though it looks mostly like
1N/Acode, it's not. It's embedded documentation such as would be used by
1N/Athe pod2man, pod2html, or pod2text programs. The Perl compiler ignores
1N/Apods entirely, just as the translators ignore code. Here's an example of
1N/Asome pods describing the informal interface:
1N/A Person - class to implement people
1N/A $count = Person->population;
1N/A #######################
1N/A # object data methods #
1N/A #######################
1N/A ### get versions ###
1N/A ### set versions ###
1N/A $ob->peers( "Norbert", "Rhys", "Phineas" );
1N/A ########################
1N/A # other object methods #
1N/A ########################
1N/A $phrase = $ob->exclaim;
1N/A $ob->happy_birthday;
1N/A The Person class implements dah dee dah dee dah....
1N/AThat's all there is to the matter of interface versus implementation.
1N/AA programmer who opens up the module and plays around with all the private
1N/Alittle shiny bits that were safely locked up behind the interface contract
1N/Ahas voided the warranty, and you shouldn't worry about their fate.
1N/ASuppose you later want to change the class to implement better names.
1N/APerhaps you'd like to support both given names (called Christian names,
1N/Airrespective of one's religion) and family names (called surnames), plus
1N/Anicknames and titles. If users of your Person class have been properly
1N/Aaccessing it through its documented interface, then you can easily change
1N/Athe underlying implementation. If they haven't, then they lose and
1N/Ait's their fault for breaking the contract and voiding their warranty.
1N/ATo do this, we'll make another class, this one called Fullname. What's
1N/Athe Fullname class look like? To answer that question, you have to
1N/Afirst figure out how you want to use it. How about we use it this way:
1N/A $him = Person->new();
1N/A $him->fullname->title("St");
1N/A $him->fullname->christian("Thomas");
1N/A $him->fullname->surname("Aquinas");
1N/A $him->fullname->nickname("Tommy");
1N/A printf "His normal name is %s\n", $him->name;
1N/A printf "But his real name is %s\n", $him->fullname->as_string;
1N/AOk. To do this, we'll change Person::new() so that it supports
1N/Aa full name field this way:
1N/A $self->{FULLNAME} = Fullname->new();
1N/A $self->{AGE} = undef;
1N/A $self->{PEERS} = [];
1N/A $self->{"_CENSUS"} = \$Census;
1N/A bless ($self, $class);
1N/A ++ ${ $self->{"_CENSUS"} };
1N/A return $self->{FULLNAME};
1N/AThen to support old code, define Person::name() this way:
1N/A return $self->{FULLNAME}->nickname(@_)
1N/A || $self->{FULLNAME}->christian(@_);
1N/AHere's the Fullname class. We'll use the same technique
1N/Aof using a hash reference to hold data fields, and methods
1N/Aby the appropriate name to access them:
1N/A bless ($self, $class);
1N/A if (@_) { $self->{CHRISTIAN} = shift }
1N/A return $self->{CHRISTIAN};
1N/A if (@_) { $self->{SURNAME} = shift }
1N/A return $self->{SURNAME};
1N/A if (@_) { $self->{NICK} = shift }
1N/A return $self->{NICK};
1N/A if (@_) { $self->{TITLE} = shift }
1N/A return $self->{TITLE};
1N/A my $name = join(" ", @$self{'CHRISTIAN', 'SURNAME'});
1N/A if ($self->{TITLE}) {
1N/A $name = $self->{TITLE} . " " . $name;
1N/AFinally, here's the test program:
1N/A sub END { show_census() }
1N/A sub show_census () {
1N/A printf "Current population: %d\n", Person->population;
1N/A my $him = Person->new();
1N/A $him->fullname->christian("Thomas");
1N/A $him->fullname->surname("Aquinas");
1N/A $him->fullname->nickname("Tommy");
1N/A $him->fullname->title("St");
1N/A printf "%s is really %s.\n", $him->name, $him->fullname->as_string;
1N/A printf "%s's age: %d.\n", $him->name, $him->age;
1N/A $him->happy_birthday;
1N/A printf "%s's age: %d.\n", $him->name, $him->age;
1N/AObject-oriented programming systems all support some notion of
1N/Ainheritance. Inheritance means allowing one class to piggy-back on
1N/Atop of another one so you don't have to write the same code again and
1N/Aagain. It's about software reuse, and therefore related to Laziness,
1N/Atraditional modules are also a form of code reuse, but a simpler one than
1N/Athe true inheritance that you find in object modules.)
1N/ASometimes the syntax of inheritance is built into the core of the
1N/Alanguage, and sometimes it's not. Perl has no special syntax for
1N/Aspecifying the class (or classes) to inherit from. Instead, it's all
1N/Astrictly in the semantics. Each package can have a variable called @ISA,
1N/Awhich governs (method) inheritance. If you try to call a method on an
1N/Aobject or class, and that method is not found in that object's package,
1N/APerl then looks to @ISA for other packages to go looking through in
1N/Asearch of the missing method.
1N/ALike the special per-package variables recognized by Exporter (such as
1N/A@EXPORT, @EXPORT_OK, @EXPORT_FAIL, %EXPORT_TAGS, and $VERSION), the @ISA
1N/Aarray I<must> be a package-scoped global and not a file-scoped lexical
1N/Acreated via my(). Most classes have just one item in their @ISA array.
1N/AIn this case, we have what's called "single inheritance", or SI for short.
1N/ANot a lot to it, eh? All it's doing so far is loading in another
1N/Aclass and stating that this one will inherit methods from that
1N/Aother class if need be. We have given it none of its own methods.
1N/AWe rely upon an Employee to behave just like a Person.
1N/ASetting up an empty class like this is called the "empty subclass test";
1N/Athat is, making a derived class that does nothing but inherit from a
1N/Abase class. If the original base class has been designed properly,
1N/Athen the new derived class can be used as a drop-in replacement for the
1N/Aold one. This means you should be able to write a program like this:
1N/A my $empl = Employee->new();
1N/A $empl->name("Jason");
1N/A printf "%s is age %d.\n", $empl->name, $empl->age;
1N/ABy proper design, we mean always using the two-argument form of bless(),
1N/Aavoiding direct access of global data, and not exporting anything. If you
1N/Alook back at the Person::new() function we defined above, we were careful
1N/Ato do that. There's a bit of package data used in the constructor,
1N/Abut the reference to this is stored on the object itself and all other
1N/Amethods access package data via that reference, so we should be ok.
1N/AWhat do we mean by the Person::new() function -- isn't that actually
1N/Aa method? Well, in principle, yes. A method is just a function that
1N/Aexpects as its first argument a class name (package) or object
1N/A(blessed reference). Person::new() is the function that both the
1N/AC<< Person->new() >> method and the C<< Employee->new() >> method end
1N/Aup calling. Understand that while a method call looks a lot like a
1N/Afunction call, they aren't really quite the same, and if you treat them
1N/Aas the same, you'll very soon be left with nothing but broken programs.
1N/AFirst, the actual underlying calling conventions are different: method
1N/Acalls get an extra argument. Second, function calls don't do inheritance,
1N/A Method Call Resulting Function Call
1N/A ----------- ------------------------
1N/A Person->new() Person::new("Person")
1N/A Employee->new() Person::new("Employee")
1N/ASo don't use function calls when you mean to call a method.
1N/AIf an employee is just a Person, that's not all too very interesting.
1N/ASo let's add some other methods. We'll give our employee
1N/Adata fields to access their salary, their employee ID, and their
1N/AIf you're getting a little tired of creating all these nearly identical
1N/Amethods just to get at the object's data, do not despair. Later,
1N/Awe'll describe several different convenience mechanisms for shortening
1N/Athis up. Meanwhile, here's the straight-forward way:
1N/A if (@_) { $self->{SALARY} = shift }
1N/A return $self->{SALARY};
1N/A if (@_) { $self->{ID} = shift }
1N/A if (@_) { $self->{START_DATE} = shift }
1N/A return $self->{START_DATE};
1N/A=head2 Overridden Methods
1N/AWhat happens when both a derived class and its base class have the same
1N/Amethod defined? Well, then you get the derived class's version of that
1N/Amethod. For example, let's say that we want the peers() method called on
1N/Aan employee to act a bit differently. Instead of just returning the list
1N/Aof peer names, let's return slightly different strings. So doing this:
1N/A $empl->peers("Peter", "Paul", "Mary");
1N/A printf "His peers are: %s\n", join(", ", $empl->peers);
1N/A His peers are: PEON=PETER, PEON=PAUL, PEON=MARY
1N/A if (@_) { @{ $self->{PEERS} } = @_ }
1N/A return map { "PEON=\U$_" } @{ $self->{PEERS} };
1N/AThere, we've just demonstrated the high-falutin' concept known in certain
1N/Acircles as I<polymorphism>. We've taken on the form and behaviour of
1N/Aan existing object, and then we've altered it to suit our own purposes.
1N/AThis is a form of Laziness. (Getting polymorphed is also what happens
1N/Awhen the wizard decides you'd look better as a frog.)
1N/AEvery now and then you'll want to have a method call trigger both its
1N/Aderived class (also known as "subclass") version as well as its base class
1N/A(also known as "superclass") version. In practice, constructors and
1N/Adestructors are likely to want to do this, and it probably also makes
1N/Asense in the debug() method we showed previously.
1N/A confess "usage: thing->debug(level)" unless @_ == 1;
1N/A $self->{"_DEBUG"} = $level;
1N/A $Debugging = $level; # whole class
1N/A Person::debug($self, $Debugging); # don't really do this
1N/AAs you see, we turn around and call the Person package's debug() function.
1N/ABut this is far too fragile for good design. What if Person doesn't
1N/Ahave a debug() function, but is inheriting I<its> debug() method
1N/Afrom elsewhere? It would have been slightly better to say
1N/A Person->debug($Debugging);
1N/ABut even that's got too much hard-coded. It's somewhat better to say
1N/A $self->Person::debug($Debugging);
1N/AWhich is a funny way to say to start looking for a debug() method up
1N/Ain Person. This strategy is more often seen on overridden object methods
1N/Athan on overridden class methods.
1N/AThere is still something a bit off here. We've hard-coded our
1N/Asuperclass's name. This in particular is bad if you change which classes
1N/Ayou inherit from, or add others. Fortunately, the pseudoclass SUPER
1N/Acomes to the rescue here.
1N/A $self->SUPER::debug($Debugging);
1N/AThis way it starts looking in my class's @ISA. This only makes sense
1N/Afrom I<within> a method call, though. Don't try to access anything
1N/Ain SUPER:: from anywhere else, because it doesn't exist outside
1N/Aan overridden method call. Note that C<SUPER> refers to the superclass of
1N/Athe current package, I<not> to the superclass of C<$self>.
1N/AThings are getting a bit complicated here. Have we done anything
1N/Awe shouldn't? As before, one way to test whether we're designing
1N/Aa decent class is via the empty subclass test. Since we already have
1N/Aan Employee class that we're trying to check, we'd better get a new
1N/Aempty subclass that can derive from Employee. Here's one:
1N/A @ISA = qw(Employee);
1N/AAnd here's the test program:
1N/A my $boss = Boss->new();
1N/A $boss->fullname->title("Don");
1N/A $boss->fullname->surname("Pichon Alvarez");
1N/A $boss->fullname->christian("Federico Jesus");
1N/A $boss->fullname->nickname("Fred");
1N/A $boss->peers("Frank", "Felipe", "Faust");
1N/A printf "%s is age %d.\n", $boss->fullname->as_string, $boss->age;
1N/A printf "His peers are: %s\n", join(", ", $boss->peers);
1N/ARunning it, we see that we're still ok. If you'd like to dump out your
1N/Aobject in a nice format, somewhat like the way the 'x' command works in
1N/Athe debugger, you could use the Data::Dumper module from CPAN this way:
1N/A print "Here's the boss:\n";
1N/A print Dumper($boss);
1N/AWhich shows us something like this:
1N/A FULLNAME => bless( {
1N/A SURNAME => 'Pichon Alvarez',
1N/A CHRISTIAN => 'Federico Jesus'
1N/AHm.... something's missing there. What about the salary, start date,
1N/Aand ID fields? Well, we never set them to anything, even undef, so they
1N/Adon't show up in the hash's keys. The Employee class has no new() method
1N/Aof its own, and the new() method in Person doesn't know about Employees.
1N/A(Nor should it: proper OO design dictates that a subclass be allowed to
1N/Aknow about its immediate superclass, but never vice-versa.) So let's
1N/Afix up Employee::new() this way:
1N/A my $self = $class->SUPER::new();
1N/A $self->{SALARY} = undef;
1N/A $self->{ID} = undef;
1N/A $self->{START_DATE} = undef;
1N/A bless ($self, $class); # reconsecrate
1N/ANow if you dump out an Employee or Boss object, you'll find
1N/Athat new fields show up there now.
1N/A=head2 Multiple Inheritance
1N/AOk, at the risk of confusing beginners and annoying OO gurus, it's
1N/Atime to confess that Perl's object system includes that controversial
1N/Anotion known as multiple inheritance, or MI for short. All this means
1N/Ais that rather than having just one parent class who in turn might
1N/Aitself have a parent class, etc., that you can directly inherit from
1N/Atwo or more parents. It's true that some uses of MI can get you into
1N/Atrouble, although hopefully not quite so much trouble with Perl as with
1N/Adubiously-OO languages like C++.
1N/AThe way it works is actually pretty simple: just put more than one package
1N/Aname in your @ISA array. When it comes time for Perl to go finding
1N/Amethods for your object, it looks at each of these packages in order.
1N/AWell, kinda. It's actually a fully recursive, depth-first order.
1N/AConsider a bunch of @ISA arrays like this:
1N/A @First::ISA = qw( Alpha );
1N/A @Second::ISA = qw( Beta );
1N/A @Third::ISA = qw( First Second );
1N/AIf you have an object of class Third:
1N/A my $ob = Third->new();
1N/AHow do we find a spin() method (or a new() method for that matter)?
1N/ABecause the search is depth-first, classes will be looked up
1N/Ain the following order: Third, First, Alpha, Second, and Beta.
1N/AIn practice, few class modules have been seen that actually
1N/Amake use of MI. One nearly always chooses simple containership of
1N/Aone class within another over MI. That's why our Person
1N/Aobject I<contained> a Fullname object. That doesn't mean
1N/AHowever, there is one particular area where MI in Perl is rampant:
1N/Aborrowing another class's class methods. This is rather common,
1N/Aespecially with some bundled "objectless" classes,
1N/Alike Exporter, DynaLoader, AutoLoader, and SelfLoader. These classes
1N/Ado not provide constructors; they exist only so you may inherit their
1N/Aclass methods. (It's not entirely clear why inheritance was done
1N/Ahere rather than traditional module importation.)
1N/AFor example, here is the POSIX module's @ISA:
1N/A @ISA = qw(Exporter DynaLoader);
1N/AThe POSIX module isn't really an object module, but then,
1N/Aneither are Exporter or DynaLoader. They're just lending their
1N/Aclasses' behaviours to POSIX.
1N/AWhy don't people use MI for object methods much? One reason is that
1N/Ait can have complicated side-effects. For one thing, your inheritance
1N/Agraph (no longer a tree) might converge back to the same base class.
1N/AAlthough Perl guards against recursive inheritance, merely having parents
1N/Awho are related to each other via a common ancestor, incestuous though
1N/Ait sounds, is not forbidden. What if in our Third class shown above we
1N/Awanted its new() method to also call both overridden constructors in its
1N/Atwo parent classes? The SUPER notation would only find the first one.
1N/AAlso, what about if the Alpha and Beta classes both had a common ancestor,
1N/Alike Nought? If you kept climbing up the inheritance tree calling
1N/Aoverridden methods, you'd end up calling Nought::new() twice,
1N/Awhich might well be a bad idea.
1N/A=head2 UNIVERSAL: The Root of All Objects
1N/AWouldn't it be convenient if all objects were rooted at some ultimate
1N/Abase class? That way you could give every object common methods without
1N/Ahaving to go and add it to each and every @ISA. Well, it turns out that
1N/Ayou can. You don't see it, but Perl tacitly and irrevocably assumes
1N/Athat there's an extra element at the end of @ISA: the class UNIVERSAL.
1N/AIn version 5.003, there were no predefined methods there, but you could put
1N/Awhatever you felt like into it.
1N/AHowever, as of version 5.004 (or some subversive releases, like 5.003_08),
1N/AUNIVERSAL has some methods in it already. These are builtin to your Perl
1N/Abinary, so they don't take any extra time to load. Predefined methods
1N/Ainclude isa(), can(), and VERSION(). isa() tells you whether an object or
1N/Aclass "is" another one without having to traverse the hierarchy yourself:
1N/A $has_io = $fd->isa("IO::Handle");
1N/A $itza_handle = IO::Socket->isa("IO::Handle");
1N/AThe can() method, called against that object or class, reports back
1N/Awhether its string argument is a callable method name in that class.
1N/AIn fact, it gives you back a function reference to that method:
1N/A $his_print_method = $obj->can('as_string');
1N/AFinally, the VERSION method checks whether the class (or the object's
1N/Aclass) has a package global called $VERSION that's high enough, as in:
1N/A Some_Module->VERSION(3.0);
1N/A $his_vers = $ob->VERSION();
1N/AHowever, we don't usually call VERSION ourselves. (Remember that an all
1N/Auppercase function name is a Perl convention that indicates that the
1N/Afunction will be automatically used by Perl in some way.) In this case,
1N/Ait happens when you say
1N/A use Some_Module 3.0;
1N/AIf you wanted to add version checking to your Person class explained
1N/A our $VERSION = '1.1';
1N/AAnd it would make sure that you have at least that version number or
1N/Ahigher available. This is not the same as loading in that exact version
1N/Anumber. No mechanism currently exists for concurrent installation of
1N/Amultiple versions of a module. Lamentably.
1N/A=head1 Alternate Object Representations
1N/ANothing requires objects to be implemented as hash references. An object
1N/Acan be any sort of reference so long as its referent has been suitably
1N/Ablessed. That means scalar, array, and code references are also fair
1N/AA scalar would work if the object has only one datum to hold. An array
1N/Awould work for most cases, but makes inheritance a bit dodgy because
1N/Ayou have to invent new indices for the derived classes.
1N/A=head2 Arrays as Objects
1N/AIf the user of your class honors the contract and sticks to the advertised
1N/Ainterface, then you can change its underlying interface if you feel
1N/Alike it. Here's another implementation that conforms to the same
1N/Ainterface specification. This time we'll use an array reference
1N/Ainstead of a hash reference to represent the object.
1N/A my($NAME, $AGE, $PEERS) = ( 0 .. 2 );
1N/A ############################################
1N/A ## the object constructor (array version) ##
1N/A ############################################
1N/A $self->[$NAME] = undef; # this is unnecessary
1N/A $self->[$AGE] = undef; # as is this
1N/A $self->[$PEERS] = []; # but this isn't, really
1N/A if (@_) { $self->[$NAME] = shift }
1N/A return $self->[$NAME];
1N/A if (@_) { $self->[$AGE] = shift }
1N/A return $self->[$AGE];
1N/A if (@_) { @{ $self->[$PEERS] } = @_ }
1N/A return @{ $self->[$PEERS] };
1N/A 1; # so the require or use succeeds
1N/AYou might guess that the array access would be a lot faster than the
1N/Ahash access, but they're actually comparable. The array is a I<little>
1N/Abit faster, but not more than ten or fifteen percent, even when you
1N/Areplace the variables above like $AGE with literal numbers, like 1.
1N/AA bigger difference between the two approaches can be found in memory use.
1N/AA hash representation takes up more memory than an array representation
1N/Abecause you have to allocate memory for the keys as well as for the values.
1N/AHowever, it really isn't that bad, especially since as of version 5.004,
1N/Amemory is only allocated once for a given hash key, no matter how many
1N/Ahashes have that key. It's expected that sometime in the future, even
1N/Athese differences will fade into obscurity as more efficient underlying
1N/Arepresentations are devised.
1N/AStill, the tiny edge in speed (and somewhat larger one in memory)
1N/Ais enough to make some programmers choose an array representation
1N/Afor simple classes. There's still a little problem with
1N/Ascalability, though, because later in life when you feel
1N/Alike creating subclasses, you'll find that hashes just work
1N/A=head2 Closures as Objects
1N/AUsing a code reference to represent an object offers some fascinating
1N/Apossibilities. We can create a new anonymous function (closure) who
1N/Aalone in all the world can see the object's data. This is because we
1N/Aput the data into an anonymous hash that's lexically visible only to
1N/Athe closure we create, bless, and return as the object. This object's
1N/Amethods turn around and call the closure as a regular subroutine call,
1N/Apassing it the field we want to affect. (Yes,
1N/Athe double-function call is slow, but if you wanted fast, you wouldn't
1N/Abe using objects at all, eh? :-)
1N/AUse would be similar to before:
1N/A $him = Person->new();
1N/A $him->name("Jason");
1N/A $him->peers( [ "Norbert", "Rhys", "Phineas" ] );
1N/A printf "%s is %d years old.\n", $him->name, $him->age;
1N/A print "His peers are: ", join(", ", @{$him->peers}), "\n";
1N/Abut the implementation would be radically, perhaps even sublimely
1N/A if (@_) { $self->{$field} = shift }
1N/A return $self->{$field};
1N/A bless($closure, $class);
1N/A sub name { &{ $_[0] }("NAME", @_[ 1 .. $#_ ] ) }
1N/A sub age { &{ $_[0] }("AGE", @_[ 1 .. $#_ ] ) }
1N/A sub peers { &{ $_[0] }("PEERS", @_[ 1 .. $#_ ] ) }
1N/ABecause this object is hidden behind a code reference, it's probably a bit
1N/Amysterious to those whose background is more firmly rooted in standard
1N/Aprocedural or object-based programming languages than in functional
1N/Aprogramming languages whence closures derive. The object
1N/Acreated and returned by the new() method is itself not a data reference
1N/Aas we've seen before. It's an anonymous code reference that has within
1N/Ait access to a specific version (lexical binding and instantiation)
1N/Aof the object's data, which are stored in the private variable $self.
1N/AAlthough this is the same function each time, it contains a different
1N/AWhen a method like C<$him-E<gt>name("Jason")> is called, its implicit
1N/Azeroth argument is the invoking object--just as it is with all method
1N/Acalls. But in this case, it's our code reference (something like a
1N/Afunction pointer in C++, but with deep binding of lexical variables).
1N/AThere's not a lot to be done with a code reference beyond calling it, so
1N/Athat's just what we do when we say C<&{$_[0]}>. This is just a regular
1N/Afunction call, not a method call. The initial argument is the string
1N/A"NAME", and any remaining arguments are whatever had been passed to the
1N/AOnce we're executing inside the closure that had been created in new(),
1N/Athe $self hash reference suddenly becomes visible. The closure grabs
1N/Aits first argument ("NAME" in this case because that's what the name()
1N/Amethod passed it), and uses that string to subscript into the private
1N/Ahash hidden in its unique version of $self.
1N/ANothing under the sun will allow anyone outside the executing method to
1N/Abe able to get at this hidden data. Well, nearly nothing. You I<could>
1N/Asingle step through the program using the debugger and find out the
1N/Apieces while you're in the method, but everyone else is out of luck.
1N/AThere, if that doesn't excite the Scheme folks, then I just don't know
1N/Awhat will. Translation of this technique into C++, Java, or any other
1N/Abraindead-static language is left as a futile exercise for aficionados
1N/AYou could even add a bit of nosiness via the caller() function and
1N/Amake the closure refuse to operate unless called via its own package.
1N/AThis would no doubt satisfy certain fastidious concerns of programming
1N/Apolice and related puritans.
1N/AIf you were wondering when Hubris, the third principle virtue of a
1N/Aprogrammer, would come into play, here you have it. (More seriously,
1N/AHubris is just the pride in craftsmanship that comes from having written
1N/Aa sound bit of well-designed code.)
1N/A=head1 AUTOLOAD: Proxy Methods
1N/AAutoloading is a way to intercept calls to undefined methods. An autoload
1N/Aroutine may choose to create a new function on the fly, either loaded
1N/Afrom disk or perhaps just eval()ed right there. This define-on-the-fly
1N/Astrategy is why it's called autoloading.
1N/ABut that's only one possible approach. Another one is to just
1N/Ahave the autoloaded method itself directly provide the
1N/Arequested service. When used in this way, you may think
1N/Aof autoloaded methods as "proxy" methods.
1N/AWhen Perl tries to call an undefined function in a particular package
1N/Aand that function is not defined, it looks for a function in
1N/Athat same package called AUTOLOAD. If one exists, it's called
1N/Awith the same arguments as the original function would have had.
1N/AThe fully-qualified name of the function is stored in that package's
1N/Aglobal variable $AUTOLOAD. Once called, the function can do anything
1N/Ait would like, including defining a new function by the right name, and
1N/Athen doing a really fancy kind of C<goto> right to it, erasing itself
1N/AWhat does this have to do with objects? After all, we keep talking about
1N/Afunctions, not methods. Well, since a method is just a function with
1N/Aan extra argument and some fancier semantics about where it's found,
1N/Awe can use autoloading for methods, too. Perl doesn't start looking
1N/Afor an AUTOLOAD method until it has exhausted the recursive hunt up
1N/Athrough @ISA, though. Some programmers have even been known to define
1N/Aa UNIVERSAL::AUTOLOAD method to trap unresolved method calls to any
1N/A=head2 Autoloaded Data Methods
1N/AYou probably began to get a little suspicious about the duplicated
1N/Acode way back earlier when we first showed you the Person class, and
1N/Athen later the Employee class. Each method used to access the
1N/Ahash fields looked virtually identical. This should have tickled
1N/Athat great programming virtue, Impatience, but for the time,
1N/Awe let Laziness win out, and so did nothing. Proxy methods can cure
1N/AInstead of writing a new function every time we want a new data field,
1N/Awe'll use the autoload mechanism to generate (actually, mimic) methods on
1N/Athe fly. To verify that we're accessing a valid member, we will check
1N/Aagainst an C<_permitted> (pronounced "under-permitted") field, which
1N/Ais a reference to a file-scoped lexical (like a C file static) hash of permitted fields in this record
1N/Acalled %fields. Why the underscore? For the same reason as the _CENSUS
1N/Afield we once used: as a marker that means "for internal use only".
1N/AHere's what the module initialization code and class
1N/Aconstructor will look like when taking this approach:
1N/A our $AUTOLOAD; # it's a package global
1N/A _permitted => \%fields,
1N/A bless $self, $class;
1N/AIf we wanted our record to have default values, we could fill those in
1N/Awhere current we have C<undef> in the %fields hash.
1N/ANotice how we saved a reference to our class data on the object itself?
1N/ARemember that it's important to access class data through the object
1N/Aitself instead of having any method reference %fields directly, or else
1N/Ayou won't have a decent inheritance.
1N/AThe real magic, though, is going to reside in our proxy method, which
1N/Awill handle all calls to undefined methods for objects of class Person
1N/A(or subclasses of Person). It has to be called AUTOLOAD. Again, it's
1N/Aall caps because it's called for us implicitly by Perl itself, not by
1N/A my $type = ref($self)
1N/A or croak "$self is not an object";
1N/A my $name = $AUTOLOAD;
1N/A $name =~ s/.*://; # strip fully-qualified portion
1N/A unless (exists $self->{_permitted}->{$name} ) {
1N/A croak "Can't access `$name' field in class $type";
1N/A return $self->{$name} = shift;
1N/A return $self->{$name};
1N/APretty nifty, eh? All we have to do to add new data fields
1N/Ais modify %fields. No new functions need be written.
1N/AI could have avoided the C<_permitted> field entirely, but I
1N/Awanted to demonstrate how to store a reference to class data on the
1N/Aobject so you wouldn't have to access that class data
1N/Adirectly from an object method.
1N/A=head2 Inherited Autoloaded Data Methods
1N/ABut what about inheritance? Can we define our Employee
1N/Aclass similarly? Yes, so long as we're careful enough.
1N/AHere's how to be careful:
1N/A our @ISA = qw(Person);
1N/A my $self = $class->SUPER::new();
1N/A foreach $element (keys %fields) {
1N/A $self->{_permitted}->{$element} = $fields{$element};
1N/A @{$self}{keys %fields} = values %fields;
1N/AOnce we've done this, we don't even need to have an
1N/AAUTOLOAD function in the Employee package, because
1N/Awe'll grab Person's version of that via inheritance,
1N/Aand it will all work out just fine.
1N/A=head1 Metaclassical Tools
1N/AEven though proxy methods can provide a more convenient approach to making
1N/Amore struct-like classes than tediously coding up data methods as
1N/Afunctions, it still leaves a bit to be desired. For one thing, it means
1N/Ayou have to handle bogus calls that you don't mean to trap via your proxy.
1N/AIt also means you have to be quite careful when dealing with inheritance,
1N/APerl programmers have responded to this by creating several different
1N/Aclass construction classes. These metaclasses are classes
1N/Athat create other classes. A couple worth looking at are
1N/AClass::Struct and Alias. These and other related metaclasses can be
1N/Afound in the modules directory on CPAN.
1N/AOne of the older ones is Class::Struct. In fact, its syntax and
1N/Ainterface were sketched out long before perl5 even solidified into a
1N/Areal thing. What it does is provide you a way to "declare" a class
1N/Aas having objects whose fields are of a specific type. The function
1N/Athat does this is called, not surprisingly enough, struct(). Because
1N/Astructures or records are not base types in Perl, each time you want to
1N/Acreate a class to provide a record-like data object, you yourself have
1N/Ato define a new() method, plus separate data-access methods for each of
1N/Athat record's fields. You'll quickly become bored with this process.
1N/AThe Class::Struct::struct() function alleviates this tedium.
1N/AHere's a simple example of using it:
1N/A use Class::Struct qw(struct);
1N/A use Jobbie; # user-defined; see below
1N/A profession => 'Jobbie', # does not call Jobbie->new()
1N/A $ob = Fred->new(profession => Jobbie->new());
1N/A $ob->many(0, "here");
1N/A $ob->many(1, "you");
1N/A print "Just set: ", $ob->many(2), "\n";
1N/A $ob->profession->salary(10_000);
1N/AYou can declare types in the struct to be basic Perl types, or
1N/Auser-defined types (classes). User types will be initialized by calling
1N/Athat class's new() method.
1N/ATake care that the C<Jobbie> object is not created automatically by the
1N/AC<Fred> class's new() method, so you should specify a C<Jobbie> object
1N/Awhen you create an instance of C<Fred>.
1N/AHere's a real-world example of using struct generation. Let's say you
1N/Awanted to override Perl's idea of gethostbyname() and gethostbyaddr() so
1N/Athat they would return objects that acted like C structures. We don't
1N/Acare about high-falutin' OO gunk. All we want is for these objects to
1N/Aact like structs in the C sense.
1N/A $h->name, inet_ntoa($h->addr);
1N/AHere's how to do this using the Class::Struct module.
1N/AThe crux is going to be this call:
1N/A struct 'Net::hostent' => [ # note bracket
1N/AWhich creates object methods of those names and types.
1N/AIt even creates a new() method for us.
1N/AWe could also have implemented our object this way:
1N/A struct 'Net::hostent' => { # note brace
1N/Aand then Class::Struct would have used an anonymous hash as the object
1N/Atype, instead of an anonymous array. The array is faster and smaller,
1N/Abut the hash works out better if you eventually want to do inheritance.
1N/ASince for this struct-like object we aren't planning on inheritance,
1N/Athis time we'll opt for better speed and size over better flexibility.
1N/AHere's the whole implementation:
1N/A package Net::hostent;
1N/A our @EXPORT = qw(gethostbyname gethostbyaddr gethost);
1N/A our @EXPORT_OK = qw(
1N/A $h_addrtype $h_length
1N/A @h_addr_list $h_addr
1N/A our %EXPORT_TAGS = ( FIELDS => [ @EXPORT_OK, @EXPORT ] );
1N/A # Class::Struct forbids use of @ISA
1N/A sub import { goto &Exporter::import }
1N/A use Class::Struct qw(struct);
1N/A struct 'Net::hostent' => [
1N/A sub addr { shift->addr_list->[0] }
1N/A my $hob = new(); # Class::Struct made this!
1N/A $h_name = $hob->[0] = $_[0];
1N/A @h_aliases = @{ $hob->[1] } = split ' ', $_[1];
1N/A $h_addrtype = $hob->[2] = $_[2];
1N/A $h_length = $hob->[3] = $_[3];
1N/A @h_addr_list = @{ $hob->[4] } = @_[ (4 .. $#_) ];
1N/A sub gethostbyname ($) { populate(CORE::gethostbyname(shift)) }
1N/A sub gethostbyaddr ($;$) {
1N/A my ($addr, $addrtype);
1N/A require Socket unless @_;
1N/A $addrtype = @_ ? shift : Socket::AF_INET();
1N/A populate(CORE::gethostbyaddr($addr, $addrtype))
1N/A if ($_[0] =~ /^\d+(?:\.\d+(?:\.\d+(?:\.\d+)?)?)?$/) {
1N/A &gethostbyaddr(Socket::inet_aton(shift));
1N/AWe've snuck in quite a fair bit of other concepts besides just dynamic
1N/Afunction prototyping, short-cut function call via C<&whatever>, and
1N/Afunction replacement with C<goto &whatever>. These all mostly make
1N/Asense from the perspective of a traditional module, but as you can see,
1N/Awe can also use them in an object module.
1N/AYou can look at other object-based, struct-like overrides of core
1N/Afunctions in the 5.004 release of Perl in File::stat, Net::hostent,
1N/ANet::netent, Net::protoent, Net::servent, Time::gmtime, Time::localtime,
1N/AUser::grent, and User::pwent. These modules have a final component
1N/Athat's all lowercase, by convention reserved for compiler pragmas,
1N/Abecause they affect the compilation and change a builtin function.
1N/AThey also have the type names that a C programmer would most expect.
1N/A=head2 Data Members as Variables
1N/AIf you're used to C++ objects, then you're accustomed to being able to
1N/Aget at an object's data members as simple variables from within a method.
1N/AThe Alias module provides for this, as well as a good bit more, such
1N/Aas the possibility of private methods that the object can call but folks
1N/Aoutside the class cannot.
1N/AHere's an example of creating a Person using the Alias module.
1N/AWhen you update these magical instance variables, you automatically
1N/Aupdate value fields in the hash. Convenient, eh?
1N/A # this is the same as before...
1N/A bless($self, $class);
1N/A our ($NAME, $AGE, $PEERS);
1N/A my $self = attr shift;
1N/A if (@_) { $NAME = shift; }
1N/A my $self = attr shift;
1N/A if (@_) { $AGE = shift; }
1N/A my $self = attr shift;
1N/A if (@_) { @PEERS = @_; }
1N/A my $self = attr shift;
1N/A return sprintf "Hi, I'm %s, age %d, working with %s",
1N/A $NAME, $AGE, join(", ", @PEERS);
1N/A sub happy_birthday {
1N/A my $self = attr shift;
1N/AThe need for the C<our> declaration is because what Alias does
1N/Ais play with package globals with the same name as the fields. To use
1N/Aglobals while C<use strict> is in effect, you have to predeclare them.
1N/AThese package variables are localized to the block enclosing the attr()
1N/Acall just as if you'd used a local() on them. However, that means that
1N/Athey're still considered global variables with temporary values, just
1N/Aas with any other local().
1N/AIt would be nice to combine Alias with
1N/Asomething like Class::Struct or Class::MethodMaker.
1N/A=head2 Object Terminology
1N/AIn the various OO literature, it seems that a lot of different words
1N/Aare used to describe only a few different concepts. If you're not
1N/Aalready an object programmer, then you don't need to worry about all
1N/Athese fancy words. But if you are, then you might like to know how to
1N/Aget at the same concepts in Perl.
1N/AFor example, it's common to call an object an I<instance> of a class
1N/Aand to call those objects' methods I<instance methods>. Data fields
1N/Apeculiar to each object are often called I<instance data> or I<object
1N/Aattributes>, and data fields common to all members of that class are
1N/AI<class data>, I<class attributes>, or I<static data members>.
1N/AAlso, I<base class>, I<generic class>, and I<superclass> all describe
1N/Athe same notion, whereas I<derived class>, I<specific class>, and
1N/AI<subclass> describe the other related one.
1N/AC++ programmers have I<static methods> and I<virtual methods>,
1N/Abut Perl only has I<class methods> and I<object methods>.
1N/AActually, Perl only has methods. Whether a method gets used
1N/Aas a class or object method is by usage only. You could accidentally
1N/Acall a class method (one expecting a string argument) on an
1N/Aobject (one expecting a reference), or vice versa.
1N/AFrom the C++ perspective, all methods in Perl are virtual.
1N/AThis, by the way, is why they are never checked for function
1N/Aprototypes in the argument list as regular builtin and user-defined
1N/ABecause a class is itself something of an object, Perl's classes can be
1N/Ataken as describing both a "class as meta-object" (also called I<object
1N/Afactory>) philosophy and the "class as type definition" (I<declaring>
1N/Abehaviour, not I<defining> mechanism) idea. C++ supports the latter
1N/Anotion, but not the former.
1N/AThe following manpages will doubtless provide more
1N/Abackground for this one:
1N/AL<perlboot> is a kinder, gentler introduction to object-oriented
1N/AL<perltooc> provides more detail on class data.
1N/ASome modules which might prove interesting are Class::Accessor,
1N/AClass::Class, Class::Contract, Class::Data::Inheritable,
1N/AClass::MethodMaker and Tie::SecureHash
1N/A=head1 AUTHOR AND COPYRIGHT
1N/ACopyright (c) 1997, 1998 Tom Christiansen
1N/AThis documentation is free; you can redistribute it
and/or modify it
1N/Aunder the same terms as Perl itself.
1N/AIrrespective of its distribution, all code examples in this file
1N/Aare hereby placed into the public domain. You are permitted and
1N/Aencouraged to use this code in your own programs for fun
1N/Aor for profit as you see fit. A simple comment in the code giving
1N/Acredit would be courteous but is not required.
1N/A=head2 Acknowledgments
1N/Aand many others for their helpful comments.