+++ /dev/null
-=head1 NAME
-
-perlboot - Beginner's Object-Oriented Tutorial
-
-=head1 DESCRIPTION
-
-If you're not familiar with objects from other languages, some of the
-other Perl object documentation may be a little daunting, such as
-L<perlobj>, a basic reference in using objects, and L<perltoot>, which
-introduces readers to the peculiarities of Perl's object system in a
-tutorial way.
-
-So, let's take a different approach, presuming no prior object
-experience. It helps if you know about subroutines (L<perlsub>),
-references (L<perlref> et. seq.), and packages (L<perlmod>), so become
-familiar with those first if you haven't already.
-
-=head2 If we could talk to the animals...
-
-Let's let the 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. So let's create
-an entire pasture:
-
- # Cow::speak, Horse::speak, Sheep::speak as before
- @pasture = qw(Cow Cow Horse Sheep Sheep);
- foreach $animal (@pasture) {
- &{$animal."::speak"};
- }
-
-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 de-referencing there is pretty nasty.
-We're counting on C<no strict refs> mode, certainly not recommended
-for larger programs. And why was that necessary? Because the name of
-the package seems to be inseparable from the name of the subroutine we
-want to invoke within that package.
-
-Or is it?
-
-=head2 Introducing the method invocation arrow
-
-For now, let's say that C<< Class->method >> invokes subroutine
-C<method> in package C<Class>. (Here, "Class" is used in its
-"category" meaning, not its "scholastic" meaning.) That's not
-completely accurate, but we'll do this one step at a time. Now let's
-use it like so:
-
- # Cow::speak, Horse::speak, Sheep::speak as before
- 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. Same number of characters, all constant, no
-variables. But yet, the parts are separable now. Watch:
-
- $a = "Cow";
- $a->speak; # invokes Cow->speak
-
-Ahh! Now that the package name has been parted from the subroutine
-name, we can use a variable package name. And this time, we've got
-something that works even when C<use strict refs> is enabled.
-
-=head2 Invoking a barnyard
-
-Let's take that new 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";
- }
-
- @pasture = qw(Cow Cow Horse Sheep Sheep);
- foreach $animal (@pasture) {
- $animal->speak;
- }
-
-There! Now we have the animals all talking, and safely at that,
-without the use of symbolic coderefs.
-
-But look at all that common code. Each of the C<speak> routines has a
-similar structure: a C<print> operator and a string that contains
-common text, except for two of the words. It'd be nice if we could
-factor out the commonality, in case we decide later to change it all
-to C<says> instead of C<goes>.
-
-And we actually have a way of doing that without much fuss, but we
-have to hear a bit more about what the method invocation arrow is
-actually doing for us.
-
-=head2 The extra parameter of method invocation
-
-The invocation of:
-
- Class->method(@args)
-
-attempts to invoke subroutine C<Class::method> as:
-
- Class::method("Class", @args);
-
-(If the subroutine can't be found, "inheritance" kicks in, but we'll
-get to that later.) This means that we get the class name as the
-first parameter (the only parameter, if no arguments are given). So
-we can rewrite the C<Sheep> speaking subroutine as:
-
- sub Sheep::speak {
- my $class = shift;
- print "a $class goes baaaah!\n";
- }
-
-And 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, C<$class> will get the value appropriate for that
-subroutine. But once again, we have a lot of similar structure. Can
-we factor that out even further? Yes, by calling another method in
-the same class.
-
-=head2 Calling a second method to simplify things
-
-Let's call out from C<speak> to a helper method called C<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 we call C<< Cow->speak >>, we get a C<$class> of C<Cow> in
-C<speak>. This in turn selects the C<< Cow->sound >> method, which
-returns C<moooo>. But how different would this be for the C<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 we
-somehow share the definition for C<speak> between the Cow and the
-Horse? Yes, with inheritance!
-
-=head2 Inheriting the windpipes
-
-We'll define a common subroutine package called C<Animal>, with the
-definition for C<speak>:
-
- { package Animal;
- sub speak {
- my $class = shift;
- print "a $class goes ", $class->sound, "!\n";
- }
- }
-
-Then, for each animal, we say it "inherits" from C<Animal>, along
-with the animal-specific sound:
-
- { package Cow;
- @ISA = qw(Animal);
- sub sound { "moooo" }
- }
-
-Note the added C<@ISA> array (pronounced "is a"). We'll get to that in a minute.
-
-But what happens when we invoke C<< Cow->speak >> now?
-
-First, Perl constructs the argument list. In this case, it's just
-C<Cow>. Then Perl looks for C<Cow::speak>. But that's not there, so
-Perl checks for the inheritance array C<@Cow::ISA>. It's there,
-and contains the single name C<Animal>.
-
-Perl next checks for C<speak> inside C<Animal> instead, as in
-C<Animal::speak>. And that's found, so Perl invokes that subroutine
-with the already frozen argument list.
-
-Inside the C<Animal::speak> subroutine, C<$class> becomes C<Cow> (the
-first argument). So when we get to the step of invoking
-C<< $class->sound >>, it'll be looking for C<< Cow->sound >>, which
-gets it on the first try without looking at C<@ISA>. Success!
-
-=head2 A few notes about @ISA
-
-This magical C<@ISA> variable has declared that C<Cow> "is a" C<Animal>.
-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.
-
-If C<Animal> also had an C<@ISA>, then we'd check there too. The
-search is recursive, depth-first, left-to-right in each C<@ISA> by
-default (see L<mro> for alternatives). Typically, each C<@ISA> has
-only one element (multiple elements means multiple inheritance and
-multiple headaches), so we get a nice tree of inheritance.
-
-When we turn on C<use strict>, we'll get complaints on C<@ISA>, since
-it's not a variable containing an explicit package name, nor is it a
-lexical ("my") variable. We can't make it a lexical variable though
-(it has to belong to the package to be found by the inheritance mechanism),
-so there's a couple of straightforward ways to handle that.
-
-The easiest is to just spell the package name out:
-
- @Cow::ISA = qw(Animal);
-
-Or declare it as a package global variable:
-
- package Cow;
- our @ISA = qw(Animal);
-
-Or allow it as an implicitly named package variable:
-
- package Cow;
- use vars qw(@ISA);
- @ISA = qw(Animal);
-
-If the C<Animal> class comes from another (object-oriented) module, then
-just employ C<use base> to specify that C<Animal> should serve as the basis
-for the C<Cow> class:
-
- package Cow;
- use base qw(Animal);
-
-Now that's pretty darn simple!
-
-=head2 Overriding the methods
-
-Let's add a mouse, which can barely be heard:
-
- # Animal package from before
- { 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, C<Mouse> has its own speaking routine, so C<< Mouse->speak >>
-doesn't immediately invoke C<< Animal->speak >>. This is known as
-"overriding". In fact, we don't even need to say that a C<Mouse> is
-an C<Animal> at all, because all of the methods needed for C<speak> are
-completely defined for C<Mouse>; this is known as "duck typing":
-"If it walks like a duck and quacks like a duck, I would call it a duck"
-(James Whitcomb). However, it would probably be beneficial to allow a
-closer examination to conclude that a C<Mouse> is indeed an C<Animal>,
-so it is actually better to define C<Mouse> with C<Animal> as its base
-(that is, it is better to "derive C<Mouse> from C<Animal>").
-
-Moreover, this duplication of code could become a maintenance headache
-(though code-reuse is not actually a good reason for inheritance; good
-design practices dictate that a derived class should be usable wherever
-its base class is usable, which might not be the outcome if code-reuse
-is the sole criterion for inheritance. Just remember that a C<Mouse>
-should always act like an C<Animal>).
-
-So, let's make C<Mouse> an C<Animal>!
-
-The obvious solution is to invoke C<Animal::speak> directly:
-
- # Animal package from before
- { 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 we're using C<Animal::speak>. If we were to invoke
-C<< Animal->speak >> instead, the first parameter to C<Animal::speak>
-would automatically be C<"Animal"> rather than C<"Mouse">, so that
-the call to C<< $class->sound >> in C<Animal::speak> would become
-C<< Animal->sound >> rather than C<< Mouse->sound >>.
-
-Also, without the method arrow C<< -> >>, it becomes necessary to specify
-the first parameter to C<Animal::speak> ourselves, which is why C<$class>
-is explicitly passed: C<Animal::speak($class)>.
-
-However, invoking C<Animal::speak> directly is a mess: Firstly, it assumes
-that the C<speak> method is a member of the C<Animal> class; what if C<Animal>
-actually inherits C<speak> from its own base? Because we are no longer using
-C<< -> >> to access C<speak>, the special method look up mechanism wouldn't be
-used, so C<speak> wouldn't even be found!
-
-The second problem is more subtle: C<Animal> is now hardwired into the subroutine
-selection. Let's assume that C<Animal::speak> does exist. What happens when,
-at a later time, someone expands the class hierarchy by having C<Mouse>
-inherit from C<Mus> instead of C<Animal>. Unless the invocation of C<Animal::speak>
-is also changed to an invocation of C<Mus::speak>, centuries worth of taxonomical
-classification could be obliterated!
-
-What we have here is a fragile or leaky abstraction; it is the beginning of a
-maintenance nightmare. What we need is the ability to search for the right
-method wih as few assumptions as possible.
-
-=head2 Starting the search from a different place
-
-A I<better> solution is to tell Perl where in the inheritance chain to begin searching
-for C<speak>. This can be achieved with a modified version of the method arrow C<< -> >>:
-
- ClassName->FirstPlaceToLook::method
-
-So, the improved C<Mouse> class is:
-
- # same Animal as before
- { package Mouse;
- # same @ISA, &sound as before
- sub speak {
- my $class = shift;
- $class->Animal::speak;
- print "[but you can barely hear it!]\n";
- }
- }
-
-Using this syntax, we start with C<Animal> to find C<speak>, and then
-use all of C<Animal>'s inheritance chain if it is not found immediately.
-As usual, the first parameter to C<speak> would be C<$class>, so we no
-longer need to pass C<$class> explicitly to C<speak>.
-
-But what about the second problem? We're still hardwiring C<Animal> into
-the method lookup.
-
-=head2 The SUPER way of doing things
-
-If C<Animal> is replaced with the special placeholder C<SUPER> in that
-invocation, then the contents of C<Mouse>'s C<@ISA> are used for the
-search, beginning with C<$ISA[0]>. So, all of the problems can be fixed
-as follows:
-
- # same Animal as before
- { package Mouse;
- # same @ISA, &sound as before
- sub speak {
- my $class = shift;
- $class->SUPER::speak;
- print "[but you can barely hear it!]\n";
- }
- }
-
-In general, C<SUPER::speak> means look in the current package's C<@ISA>
-for a class that implements C<speak>, and invoke the first one found.
-The placeholder is called C<SUPER>, because many other languages refer
-to base classes as "I<super>classes", and Perl likes to be eclectic.
-
-Note that a call such as
-
- $class->SUPER::method;
-
-does I<not> look in the C<@ISA> of C<$class> unless C<$class> happens to
-be the current package.
-
-=head2 Let's review...
-
-So far, we've seen the method arrow syntax:
-
- Class->method(@args);
-
-or the equivalent:
-
- $a = "Class";
- $a->method(@args);
-
-which constructs an argument list of:
-
- ("Class", @args)
-
-and attempts to invoke:
-
- Class::method("Class", @args);
-
-However, if C<Class::method> is not found, then C<@Class::ISA> is examined
-(recursively) to locate a class (a package) that does indeed contain C<method>,
-and that subroutine is invoked instead.
-
-Using this simple syntax, we have class methods, (multiple) inheritance,
-overriding, and extending. Using just what we've seen so far, we've
-been able to factor out common code (though that's never a good reason
-for inheritance!), and provide a nice way to reuse implementations with
-variations.
-
-Now, what about data?
-
-=head2 A horse is a horse, of course of course, or is it?
-
-Let's start with the code for the C<Animal> class
-and the C<Horse> class:
-
- { package Animal;
- sub speak {
- my $class = shift;
- print "a $class goes ", $class->sound, "!\n";
- }
- }
- { package Horse;
- @ISA = qw(Animal);
- sub sound { "neigh" }
- }
-
-This lets us invoke C<< Horse->speak >> to ripple upward to
-C<Animal::speak>, calling back to C<Horse::sound> to get the specific
-sound, and the output of:
-
- a Horse goes neigh!
-
-But all of our Horse objects would have to be absolutely identical.
-If we add a subroutine, all horses automatically share it. That's
-great for making horses the same, but how do we capture the
-distinctions of an individual horse? For example, suppose we want
-to give our first horse a name. There's got to be a way to keep its
-name separate from the other horses.
-
-That is to say, we want particular instances of C<Horse> to have
-different names.
-
-In Perl, any reference can be an "instance", so let's start with the
-simplest reference that can hold a horse's name: a scalar reference.
-
- my $name = "Mr. Ed";
- my $horse = \$name;
-
-So, now C<$horse> is a reference to what will be the instance-specific
-data (the name). The final step is to turn this reference into a real
-instance of a C<Horse> by using the special operator C<bless>:
-
- bless $horse, Horse;
-
-This operator stores information about the package named C<Horse> into
-the thing pointed at by the reference. At this point, we say
-C<$horse> is an instance of C<Horse>. That is, it's a specific
-horse. The reference is otherwise unchanged, and can still be used
-with traditional dereferencing operators.
-
-=head2 Invoking an instance method
-
-The method arrow can be used on instances, as well as classes (the names
-of packages). So, let's get the sound that C<$horse> makes:
-
- my $noise = $horse->sound("some", "unnecessary", "args");
-
-To invoke C<sound>, Perl first notes that C<$horse> is a blessed
-reference (and thus an instance). It then constructs an argument
-list, as per usual.
-
-Now for the fun part: Perl takes the class in which the instance was
-blessed, in this case C<Horse>, and uses that class to locate the
-subroutine. In this case, C<Horse::sound> is found directly (without
-using inheritance). In the end, it is as though our initial line were
-written as follows:
-
- my $noise = Horse::sound($horse, "some", "unnecessary", "args");
-
-Note that the first parameter here is still the instance, not the name
-of the class as before. We'll get C<neigh> as the return value, and
-that'll end up as the C<$noise> variable above.
-
-If Horse::sound had not been found, we'd be wandering up the C<@Horse::ISA>
-array, trying to find the method in one of the superclasses. The only
-difference between a class method and an instance method is whether the
-first parameter is an instance (a blessed reference) or a class name (a
-string).
-
-=head2 Accessing the instance data
-
-Because we get the instance as the first parameter, we can now access
-the instance-specific data. In this case, let's add a way to get at
-the name:
-
- { package Horse;
- @ISA = qw(Animal);
- sub sound { "neigh" }
- sub name {
- my $self = shift;
- $$self;
- }
- }
-
-Inside C<Horse::name>, the C<@_> array contains:
-
- ($horse, "some", "unnecessary", "args")
-
-so the C<shift> stores C<$horse> into C<$self>. Then, C<$self> gets
-de-referenced with C<$$self> as normal, yielding C<"Mr. Ed">.
-
-It's traditional to C<shift> the first parameter into a variable named
-C<$self> for instance methods and into a variable named C<$class> for
-class methods.
-
-Then, the following line:
-
- print $horse->name, " says ", $horse->sound, "\n";
-
-outputs:
-
- Mr. Ed says neigh.
-
-=head2 How to build a horse
-
-Of course, if we constructed all of our horses by hand, we'd most
-likely make mistakes from time to time. We're also violating one of
-the properties of object-oriented programming, in that the "inside
-guts" of a Horse are visible. That's good if you're a veterinarian,
-but not if you just like to own horses. So, let's have the Horse
-class handle the details inside a class method:
-
- { package Horse;
- @ISA = qw(Animal);
- sub sound { "neigh" }
- sub name {
- my $self = shift; # instance method, so use $self
- $$self;
- }
- sub named {
- my $class = shift; # class method, so use $class
- my $name = shift;
- bless \$name, $class;
- }
- }
-
-Now with the new C<named> method, we can build a horse as follows:
-
- my $horse = Horse->named("Mr. Ed");
-
-Notice we're back to a class method, so the two arguments to
-C<Horse::named> are C<Horse> and C<Mr. Ed>. The C<bless> operator
-not only blesses C<\$name>, it also returns that reference.
-
-This C<Horse::named> method is called a "constructor".
-
-We've called the constructor C<named> here, so that it quickly denotes
-the constructor's argument as the name for this particular C<Horse>.
-You can use different constructors with different names for different
-ways of "giving birth" to the object (like maybe recording its
-pedigree or date of birth). However, you'll find that most people
-coming to Perl from more limited languages use a single constructor
-named C<new>, with various ways of interpreting the arguments to
-C<new>. Either style is fine, as long as you document your particular
-way of giving birth to an object. (And you I<were> going to do that,
-right?)
-
-=head2 Inheriting the constructor
-
-But was there anything specific to C<Horse> in that method? No. Therefore,
-it's also the same recipe for building anything else that inherited from
-C<Animal>, so let's put C<name> and C<named> there:
-
- { package Animal;
- sub speak {
- my $class = shift;
- print "a $class goes ", $class->sound, "!\n";
- }
- sub name {
- my $self = shift;
- $$self;
- }
- sub named {
- my $class = shift;
- my $name = shift;
- bless \$name, $class;
- }
- }
- { package Horse;
- @ISA = qw(Animal);
- sub sound { "neigh" }
- }
-
-Ahh, but what happens if we invoke C<speak> on an instance?
-
- my $horse = Horse->named("Mr. Ed");
- $horse->speak;
-
-We get a debugging value:
-
- a Horse=SCALAR(0xaca42ac) goes neigh!
-
-Why? Because the C<Animal::speak> routine is expecting a classname as
-its first parameter, not an instance. When the instance is passed in,
-we'll end up using a blessed scalar reference as a string, and that
-shows up as we saw it just now.
-
-=head2 Making a method work with either classes or instances
-
-All we need is for a method to detect if it is being called on a class
-or called on an instance. The most straightforward way is with the
-C<ref> operator. This returns a string (the classname) when used on a
-blessed reference, and an empty string when used on a string (like a
-classname). Let's modify the C<name> method first to notice the change:
-
- sub name {
- my $either = shift;
- ref $either ? $$either : "Any $either";
- }
-
-Here, the C<?:> operator comes in handy to select either the
-dereference or a derived string. Now we can use this with either an
-instance or a class. Note that I've changed the first parameter
-holder to C<$either> to show that this is intended:
-
- my $horse = Horse->named("Mr. Ed");
- print Horse->name, "\n"; # prints "Any Horse\n"
- print $horse->name, "\n"; # prints "Mr Ed.\n"
-
-and now we'll fix C<speak> to use this:
-
- sub speak {
- my $either = shift;
- print $either->name, " goes ", $either->sound, "\n";
- }
-
-And since C<sound> already worked with either a class or an instance,
-we're done!
-
-=head2 Adding parameters to a method
-
-Let's train our animals to eat:
-
- { package Animal;
- sub named {
- my $class = shift;
- my $name = shift;
- bless \$name, $class;
- }
- sub name {
- my $either = shift;
- ref $either ? $$either : "Any $either";
- }
- sub speak {
- my $either = shift;
- print $either->name, " goes ", $either->sound, "\n";
- }
- sub eat {
- my $either = shift;
- my $food = shift;
- print $either->name, " eats $food.\n";
- }
- }
- { package Horse;
- @ISA = qw(Animal);
- sub sound { "neigh" }
- }
- { package Sheep;
- @ISA = qw(Animal);
- sub sound { "baaaah" }
- }
-
-And now try it out:
-
- my $horse = Horse->named("Mr. Ed");
- $horse->eat("hay");
- Sheep->eat("grass");
-
-which prints:
-
- Mr. Ed eats hay.
- Any Sheep eats grass.
-
-An instance method with parameters gets invoked with the instance,
-and then the list of parameters. So that first invocation is like:
-
- Animal::eat($horse, "hay");
-
-=head2 More interesting instances
-
-What if an instance needs more data? Most interesting instances are
-made of many items, each of which can in turn be a reference or even
-another object. The easiest way to store these is often in a hash.
-The keys of the hash serve as the names of parts of the object (often
-called "instance variables" or "member variables"), and the
-corresponding values are, well, the values.
-
-But how do we turn the horse into a hash? Recall that an object was
-any blessed reference. We can just as easily make it a blessed hash
-reference as a blessed scalar reference, as long as everything that
-looks at the reference is changed accordingly.
-
-Let's make a sheep that has a name and a color:
-
- my $bad = bless { Name => "Evil", Color => "black" }, Sheep;
-
-so C<< $bad->{Name} >> has C<Evil>, and C<< $bad->{Color} >> has
-C<black>. But we want to make C<< $bad->name >> access the name, and
-that's now messed up because it's expecting a scalar reference. Not
-to worry, because that's pretty easy to fix up.
-
-One solution is to override C<Animal::name> and C<Animal::named> by
-defining them anew in C<Sheep>, but then any methods added later to
-C<Animal> might still mess up, and we'd have to override all of those
-too. Therefore, it's never a good idea to define the data layout in a
-way that's different from the data layout of the base classes. In fact,
-it's a good idea to use blessed hash references in all cases. Also, this
-is why it's important to have constructors do the low-level work. So,
-let's redefine C<Animal>:
-
- ## in Animal
- sub name {
- my $either = shift;
- ref $either ? $either->{Name} : "Any $either";
- }
- sub named {
- my $class = shift;
- my $name = shift;
- my $self = { Name => $name };
- bless $self, $class;
- }
-
-Of course, we still need to override C<named> in order to handle
-constructing a C<Sheep> with a certain color:
-
- ## in Sheep
- sub named {
- my ($class, $name) = @_;
- my $self = $class->SUPER::named(@_);
- $$self{Color} = $class->default_color;
- $self
- }
-
-(Note that C<@_> contains the parameters to C<named>.)
-
-What's this C<default_color>? Well, if C<named> has only the name,
-we still need to set a color, so we'll have a class-specific default color.
-For a sheep, we might define it as white:
-
- ## in Sheep
- sub default_color { "white" }
-
-Now:
-
- my $sheep = Sheep->named("Bad");
- print $sheep->{Color}, "\n";
-
-outputs:
-
- white
-
-Now, there's nothing particularly specific to C<Sheep> when it comes
-to color, so let's remove C<Sheep::named> and implement C<Animal::named>
-to handle color instead:
-
- ## in Animal
- sub named {
- my ($class, $name) = @_;
- my $self = { Name => $name, Color => $class->default_color };
- bless $self, $class;
- }
-
-And then to keep from having to define C<default_color> for each additional
-class, we'll define a method that serves as the "default default" directly
-in C<Animal>:
-
- ## in Animal
- sub default_color { "brown" }
-
-Of course, because C<name> and C<named> were the only methods that
-referenced the "structure" of the object, the rest of the methods can
-remain the same, so C<speak> still works as before.
-
-=head2 A horse of a different color
-
-But having all our horses be brown would be boring. So let's add a
-method or two to get and set the color.
-
- ## in Animal
- sub color {
- $_[0]->{Color}
- }
- sub set_color {
- $_[0]->{Color} = $_[1];
- }
-
-Note the alternate way of accessing the arguments: C<$_[0]> is used
-in-place, rather than with a C<shift>. (This saves us a bit of time
-for something that may be invoked frequently.) And now we can fix
-that color for Mr. Ed:
-
- my $horse = Horse->named("Mr. Ed");
- $horse->set_color("black-and-white");
- print $horse->name, " is colored ", $horse->color, "\n";
-
-which results in:
-
- Mr. Ed is colored black-and-white
-
-=head2 Summary
-
-So, now we have class methods, constructors, instance methods, instance
-data, and even accessors. But that's still just the beginning of what
-Perl has to offer. We haven't even begun to talk about accessors that
-double as getters and setters, destructors, indirect object notation,
-overloading, "isa" and "can" tests, the C<UNIVERSAL> class, and so on.
-That's for the rest of the Perl documentation to cover. Hopefully, this
-gets you started, though.
-
-=head1 SEE ALSO
-
-For more information, see L<perlobj> (for all the gritty details about
-Perl objects, now that you've seen the basics), L<perltoot> (the
-tutorial for those who already know objects), L<perltooc> (dealing
-with class data), L<perlbot> (for some more tricks), and books such as
-Damian Conway's excellent I<Object Oriented Perl>.
-
-Some modules which might prove interesting are Class::Accessor,
-Class::Class, Class::Contract, Class::Data::Inheritable,
-Class::MethodMaker and Tie::SecureHash
-
-=head1 COPYRIGHT
-
-Copyright (c) 1999, 2000 by Randal L. Schwartz and Stonehenge
-Consulting Services, Inc.
-
-Copyright (c) 2009 by Michael F. Witten.
-
-Permission is hereby granted to distribute this document intact with
-the Perl distribution, and in accordance with the licenses of the Perl
-distribution; derived documents must include this copyright notice
-intact.
-
-Portions of this text have been derived from Perl Training materials
-originally appearing in the I<Packages, References, Objects, and
-Modules> course taught by instructors for Stonehenge Consulting
-Services, Inc. and used with permission.
-
-Portions of this text have been derived from materials originally
-appearing in I<Linux Magazine> and used with permission.
+++ /dev/null
-=head1 NAME
-
-perlbot - Bag o' Object Tricks (the BOT)
-
-=head1 DESCRIPTION
-
-The following collection of tricks and hints is intended to whet curious
-appetites about such things as the use of instance variables and the
-mechanics of object and class relationships. The reader is encouraged to
-consult relevant textbooks for discussion of Object Oriented definitions and
-methodology. This is not intended as a tutorial for object-oriented
-programming or as a comprehensive guide to Perl's object oriented features,
-nor should it be construed as a style guide. If you're looking for tutorials,
-be sure to read L<perlboot>, L<perltoot>, and L<perltooc>.
-
-The Perl motto still holds: There's more than one way to do it.
-
-=head1 OO SCALING TIPS
-
-=over 5
-
-=item 1
-
-Do not attempt to verify the type of $self. That'll break if the class is
-inherited, when the type of $self is valid but its package isn't what you
-expect. See rule 5.
-
-=item 2
-
-If an object-oriented (OO) or indirect-object (IO) syntax was used, then the
-object is probably the correct type and there's no need to become paranoid
-about it. Perl isn't a paranoid language anyway. If people subvert the OO
-or IO syntax then they probably know what they're doing and you should let
-them do it. See rule 1.
-
-=item 3
-
-Use the two-argument form of bless(). Let a subclass use your constructor.
-See L<INHERITING A CONSTRUCTOR>.
-
-=item 4
-
-The subclass is allowed to know things about its immediate superclass, the
-superclass is allowed to know nothing about a subclass.
-
-=item 5
-
-Don't be trigger happy with inheritance. A "using", "containing", or
-"delegation" relationship (some sort of aggregation, at least) is often more
-appropriate. See L<OBJECT RELATIONSHIPS>, L<USING RELATIONSHIP WITH SDBM>,
-and L<"DELEGATION">.
-
-=item 6
-
-The object is the namespace. Make package globals accessible via the
-object. This will remove the guess work about the symbol's home package.
-See L<CLASS CONTEXT AND THE OBJECT>.
-
-=item 7
-
-IO syntax is certainly less noisy, but it is also prone to ambiguities that
-can cause difficult-to-find bugs. Allow people to use the sure-thing OO
-syntax, even if you don't like it.
-
-=item 8
-
-Do not use function-call syntax on a method. You're going to be bitten
-someday. Someone might move that method into a superclass and your code
-will be broken. On top of that you're feeding the paranoia in rule 2.
-
-=item 9
-
-Don't assume you know the home package of a method. You're making it
-difficult for someone to override that method. See L<THINKING OF CODE REUSE>.
-
-=back
-
-=head1 INSTANCE VARIABLES
-
-An anonymous array or anonymous hash can be used to hold instance
-variables. Named parameters are also demonstrated.
-
- package Foo;
-
- sub new {
- my $type = shift;
- my %params = @_;
- my $self = {};
- $self->{'High'} = $params{'High'};
- $self->{'Low'} = $params{'Low'};
- bless $self, $type;
- }
-
-
- package Bar;
-
- sub new {
- my $type = shift;
- my %params = @_;
- my $self = [];
- $self->[0] = $params{'Left'};
- $self->[1] = $params{'Right'};
- bless $self, $type;
- }
-
- package main;
-
- $a = Foo->new( 'High' => 42, 'Low' => 11 );
- print "High=$a->{'High'}\n";
- print "Low=$a->{'Low'}\n";
-
- $b = Bar->new( 'Left' => 78, 'Right' => 40 );
- print "Left=$b->[0]\n";
- print "Right=$b->[1]\n";
-
-=head1 SCALAR INSTANCE VARIABLES
-
-An anonymous scalar can be used when only one instance variable is needed.
-
- package Foo;
-
- sub new {
- my $type = shift;
- my $self;
- $self = shift;
- bless \$self, $type;
- }
-
- package main;
-
- $a = Foo->new( 42 );
- print "a=$$a\n";
-
-
-=head1 INSTANCE VARIABLE INHERITANCE
-
-This example demonstrates how one might inherit instance variables from a
-superclass for inclusion in the new class. This requires calling the
-superclass's constructor and adding one's own instance variables to the new
-object.
-
- package Bar;
-
- sub new {
- my $type = shift;
- my $self = {};
- $self->{'buz'} = 42;
- bless $self, $type;
- }
-
- package Foo;
- @ISA = qw( Bar );
-
- sub new {
- my $type = shift;
- my $self = Bar->new;
- $self->{'biz'} = 11;
- bless $self, $type;
- }
-
- package main;
-
- $a = Foo->new;
- print "buz = ", $a->{'buz'}, "\n";
- print "biz = ", $a->{'biz'}, "\n";
-
-
-
-=head1 OBJECT RELATIONSHIPS
-
-The following demonstrates how one might implement "containing" and "using"
-relationships between objects.
-
- package Bar;
-
- sub new {
- my $type = shift;
- my $self = {};
- $self->{'buz'} = 42;
- bless $self, $type;
- }
-
- package Foo;
-
- sub new {
- my $type = shift;
- my $self = {};
- $self->{'Bar'} = Bar->new;
- $self->{'biz'} = 11;
- bless $self, $type;
- }
-
- package main;
-
- $a = Foo->new;
- print "buz = ", $a->{'Bar'}->{'buz'}, "\n";
- print "biz = ", $a->{'biz'}, "\n";
-
-
-
-=head1 OVERRIDING SUPERCLASS METHODS
-
-The following example demonstrates how to override a superclass method and
-then call the overridden method. The B<SUPER> pseudo-class allows the
-programmer to call an overridden superclass method without actually knowing
-where that method is defined.
-
- package Buz;
- sub goo { print "here's the goo\n" }
-
- package Bar; @ISA = qw( Buz );
- sub google { print "google here\n" }
-
- package Baz;
- sub mumble { print "mumbling\n" }
-
- package Foo;
- @ISA = qw( Bar Baz );
-
- sub new {
- my $type = shift;
- bless [], $type;
- }
- sub grr { print "grumble\n" }
- sub goo {
- my $self = shift;
- $self->SUPER::goo();
- }
- sub mumble {
- my $self = shift;
- $self->SUPER::mumble();
- }
- sub google {
- my $self = shift;
- $self->SUPER::google();
- }
-
- package main;
-
- $foo = Foo->new;
- $foo->mumble;
- $foo->grr;
- $foo->goo;
- $foo->google;
-
-Note that C<SUPER> refers to the superclasses of the current package
-(C<Foo>), not to the superclasses of C<$self>.
-
-
-=head1 USING RELATIONSHIP WITH SDBM
-
-This example demonstrates an interface for the SDBM class. This creates a
-"using" relationship between the SDBM class and the new class Mydbm.
-
- package Mydbm;
-
- require SDBM_File;
- require Tie::Hash;
- @ISA = qw( Tie::Hash );
-
- sub TIEHASH {
- my $type = shift;
- my $ref = SDBM_File->new(@_);
- bless {'dbm' => $ref}, $type;
- }
- sub FETCH {
- my $self = shift;
- my $ref = $self->{'dbm'};
- $ref->FETCH(@_);
- }
- sub STORE {
- my $self = shift;
- if (defined $_[0]){
- my $ref = $self->{'dbm'};
- $ref->STORE(@_);
- } else {
- die "Cannot STORE an undefined key in Mydbm\n";
- }
- }
-
- package main;
- use Fcntl qw( O_RDWR O_CREAT );
-
- tie %foo, "Mydbm", "Sdbm", O_RDWR|O_CREAT, 0640;
- $foo{'bar'} = 123;
- print "foo-bar = $foo{'bar'}\n";
-
- tie %bar, "Mydbm", "Sdbm2", O_RDWR|O_CREAT, 0640;
- $bar{'Cathy'} = 456;
- print "bar-Cathy = $bar{'Cathy'}\n";
-
-=head1 THINKING OF CODE REUSE
-
-One strength of Object-Oriented languages is the ease with which old code
-can use new code. The following examples will demonstrate first how one can
-hinder code reuse and then how one can promote code reuse.
-
-This first example illustrates a class which uses a fully-qualified method
-call to access the "private" method BAZ(). The second example will show
-that it is impossible to override the BAZ() method.
-
- package FOO;
-
- sub new {
- my $type = shift;
- bless {}, $type;
- }
- sub bar {
- my $self = shift;
- $self->FOO::private::BAZ;
- }
-
- package FOO::private;
-
- sub BAZ {
- print "in BAZ\n";
- }
-
- package main;
-
- $a = FOO->new;
- $a->bar;
-
-Now we try to override the BAZ() method. We would like FOO::bar() to call
-GOOP::BAZ(), but this cannot happen because FOO::bar() explicitly calls
-FOO::private::BAZ().
-
- package FOO;
-
- sub new {
- my $type = shift;
- bless {}, $type;
- }
- sub bar {
- my $self = shift;
- $self->FOO::private::BAZ;
- }
-
- package FOO::private;
-
- sub BAZ {
- print "in BAZ\n";
- }
-
- package GOOP;
- @ISA = qw( FOO );
- sub new {
- my $type = shift;
- bless {}, $type;
- }
-
- sub BAZ {
- print "in GOOP::BAZ\n";
- }
-
- package main;
-
- $a = GOOP->new;
- $a->bar;
-
-To create reusable code we must modify class FOO, flattening class
-FOO::private. The next example shows a reusable class FOO which allows the
-method GOOP::BAZ() to be used in place of FOO::BAZ().
-
- package FOO;
-
- sub new {
- my $type = shift;
- bless {}, $type;
- }
- sub bar {
- my $self = shift;
- $self->BAZ;
- }
-
- sub BAZ {
- print "in BAZ\n";
- }
-
- package GOOP;
- @ISA = qw( FOO );
-
- sub new {
- my $type = shift;
- bless {}, $type;
- }
- sub BAZ {
- print "in GOOP::BAZ\n";
- }
-
- package main;
-
- $a = GOOP->new;
- $a->bar;
-
-=head1 CLASS CONTEXT AND THE OBJECT
-
-Use the object to solve package and class context problems. Everything a
-method needs should be available via the object or should be passed as a
-parameter to the method.
-
-A class will sometimes have static or global data to be used by the
-methods. A subclass may want to override that data and replace it with new
-data. When this happens the superclass may not know how to find the new
-copy of the data.
-
-This problem can be solved by using the object to define the context of the
-method. Let the method look in the object for a reference to the data. The
-alternative is to force the method to go hunting for the data ("Is it in my
-class, or in a subclass? Which subclass?"), and this can be inconvenient
-and will lead to hackery. It is better just to let the object tell the
-method where that data is located.
-
- package Bar;
-
- %fizzle = ( 'Password' => 'XYZZY' );
-
- sub new {
- my $type = shift;
- my $self = {};
- $self->{'fizzle'} = \%fizzle;
- bless $self, $type;
- }
-
- sub enter {
- my $self = shift;
-
- # Don't try to guess if we should use %Bar::fizzle
- # or %Foo::fizzle. The object already knows which
- # we should use, so just ask it.
- #
- my $fizzle = $self->{'fizzle'};
-
- print "The word is ", $fizzle->{'Password'}, "\n";
- }
-
- package Foo;
- @ISA = qw( Bar );
-
- %fizzle = ( 'Password' => 'Rumple' );
-
- sub new {
- my $type = shift;
- my $self = Bar->new;
- $self->{'fizzle'} = \%fizzle;
- bless $self, $type;
- }
-
- package main;
-
- $a = Bar->new;
- $b = Foo->new;
- $a->enter;
- $b->enter;
-
-=head1 INHERITING A CONSTRUCTOR
-
-An inheritable constructor should use the second form of bless() which allows
-blessing directly into a specified class. Notice in this example that the
-object will be a BAR not a FOO, even though the constructor is in class FOO.
-
- package FOO;
-
- sub new {
- my $type = shift;
- my $self = {};
- bless $self, $type;
- }
-
- sub baz {
- print "in FOO::baz()\n";
- }
-
- package BAR;
- @ISA = qw(FOO);
-
- sub baz {
- print "in BAR::baz()\n";
- }
-
- package main;
-
- $a = BAR->new;
- $a->baz;
-
-=head1 DELEGATION
-
-Some classes, such as SDBM_File, cannot be effectively subclassed because
-they create foreign objects. Such a class can be extended with some sort of
-aggregation technique such as the "using" relationship mentioned earlier or
-by delegation.
-
-The following example demonstrates delegation using an AUTOLOAD() function to
-perform message-forwarding. This will allow the Mydbm object to behave
-exactly like an SDBM_File object. The Mydbm class could now extend the
-behavior by adding custom FETCH() and STORE() methods, if this is desired.
-
- package Mydbm;
-
- require SDBM_File;
- require Tie::Hash;
- @ISA = qw(Tie::Hash);
-
- sub TIEHASH {
- my $type = shift;
- my $ref = SDBM_File->new(@_);
- bless {'delegate' => $ref};
- }
-
- sub AUTOLOAD {
- my $self = shift;
-
- # The Perl interpreter places the name of the
- # message in a variable called $AUTOLOAD.
-
- # DESTROY messages should never be propagated.
- return if $AUTOLOAD =~ /::DESTROY$/;
-
- # Remove the package name.
- $AUTOLOAD =~ s/^Mydbm:://;
-
- # Pass the message to the delegate.
- $self->{'delegate'}->$AUTOLOAD(@_);
- }
-
- package main;
- use Fcntl qw( O_RDWR O_CREAT );
-
- tie %foo, "Mydbm", "adbm", O_RDWR|O_CREAT, 0640;
- $foo{'bar'} = 123;
- print "foo-bar = $foo{'bar'}\n";
-
-=head1 SEE ALSO
-
-L<perlboot>, L<perltoot>, L<perltooc>.
+++ /dev/null
-=head1 NAME
-
-perltooc - Tom's OO Tutorial for Class Data in Perl
-
-=head1 DESCRIPTION
-
-When designing an object class, you are sometimes faced with the situation
-of wanting common state shared by all objects of that class.
-Such I<class attributes> act somewhat like global variables for the entire
-class, but unlike program-wide globals, class attributes have meaning only to
-the class itself.
-
-Here are a few examples where class attributes might come in handy:
-
-=over 4
-
-=item *
-
-to keep a count of the objects you've created, or how many are
-still extant.
-
-=item *
-
-to extract the name or file descriptor for a logfile used by a debugging
-method.
-
-=item *
-
-to access collective data, like the total amount of cash dispensed by
-all ATMs in a network in a given day.
-
-=item *
-
-to access the last object created by a class, or the most accessed object,
-or to retrieve a list of all objects.
-
-=back
-
-Unlike a true global, class attributes should not be accessed directly.
-Instead, their state should be inspected, and perhaps altered, only
-through the mediated access of I<class methods>. These class attributes
-accessor methods are similar in spirit and function to accessors used
-to manipulate the state of instance attributes on an object. They provide a
-clear firewall between interface and implementation.
-
-You should allow access to class attributes through either the class
-name or any object of that class. If we assume that $an_object is of
-type Some_Class, and the &Some_Class::population_count method accesses
-class attributes, then these two invocations should both be possible,
-and almost certainly equivalent.
-
- Some_Class->population_count()
- $an_object->population_count()
-
-The question is, where do you store the state which that method accesses?
-Unlike more restrictive languages like C++, where these are called
-static data members, Perl provides no syntactic mechanism to declare
-class attributes, any more than it provides a syntactic mechanism to
-declare instance attributes. Perl provides the developer with a broad
-set of powerful but flexible features that can be uniquely crafted to
-the particular demands of the situation.
-
-A class in Perl is typically implemented in a module. A module consists
-of two complementary feature sets: a package for interfacing with the
-outside world, and a lexical file scope for privacy. Either of these
-two mechanisms can be used to implement class attributes. That means you
-get to decide whether to put your class attributes in package variables
-or to put them in lexical variables.
-
-And those aren't the only decisions to make. If you choose to use package
-variables, you can make your class attribute accessor methods either ignorant
-of inheritance or sensitive to it. If you choose lexical variables,
-you can elect to permit access to them from anywhere in the entire file
-scope, or you can limit direct data access exclusively to the methods
-implementing those attributes.
-
-=head1 Class Data in a Can
-
-One of the easiest ways to solve a hard problem is to let someone else
-do it for you! In this case, Class::Data::Inheritable (available on a
-CPAN near you) offers a canned solution to the class data problem
-using closures. So before you wade into this document, consider
-having a look at that module.
-
-
-=head1 Class Data as Package Variables
-
-Because a class in Perl is really just a package, using package variables
-to hold class attributes is the most natural choice. This makes it simple
-for each class to have its own class attributes. Let's say you have a class
-called Some_Class that needs a couple of different attributes that you'd
-like to be global to the entire class. The simplest thing to do is to
-use package variables like $Some_Class::CData1 and $Some_Class::CData2
-to hold these attributes. But we certainly don't want to encourage
-outsiders to touch those data directly, so we provide methods
-to mediate access.
-
-In the accessor methods below, we'll for now just ignore the first
-argument--that part to the left of the arrow on method invocation, which
-is either a class name or an object reference.
-
- package Some_Class;
- sub CData1 {
- shift; # XXX: ignore calling class/object
- $Some_Class::CData1 = shift if @_;
- return $Some_Class::CData1;
- }
- sub CData2 {
- shift; # XXX: ignore calling class/object
- $Some_Class::CData2 = shift if @_;
- return $Some_Class::CData2;
- }
-
-This technique is highly legible and should be completely straightforward
-to even the novice Perl programmer. By fully qualifying the package
-variables, they stand out clearly when reading the code. Unfortunately,
-if you misspell one of these, you've introduced an error that's hard
-to catch. It's also somewhat disconcerting to see the class name itself
-hard-coded in so many places.
-
-Both these problems can be easily fixed. Just add the C<use strict>
-pragma, then pre-declare your package variables. (The C<our> operator
-will be new in 5.6, and will work for package globals just like C<my>
-works for scoped lexicals.)
-
- package Some_Class;
- use strict;
- our($CData1, $CData2); # our() is new to perl5.6
- sub CData1 {
- shift; # XXX: ignore calling class/object
- $CData1 = shift if @_;
- return $CData1;
- }
- sub CData2 {
- shift; # XXX: ignore calling class/object
- $CData2 = shift if @_;
- return $CData2;
- }
-
-
-As with any other global variable, some programmers prefer to start their
-package variables with capital letters. This helps clarity somewhat, but
-by no longer fully qualifying the package variables, their significance
-can be lost when reading the code. You can fix this easily enough by
-choosing better names than were used here.
-
-=head2 Putting All Your Eggs in One Basket
-
-Just as the mindless enumeration of accessor methods for instance attributes
-grows tedious after the first few (see L<perltoot>), so too does the
-repetition begin to grate when listing out accessor methods for class
-data. Repetition runs counter to the primary virtue of a programmer:
-Laziness, here manifesting as that innate urge every programmer feels
-to factor out duplicate code whenever possible.
-
-Here's what to do. First, make just one hash to hold all class attributes.
-
- package Some_Class;
- use strict;
- our %ClassData = ( # our() is new to perl5.6
- CData1 => "",
- CData2 => "",
- );
-
-Using closures (see L<perlref>) and direct access to the package symbol
-table (see L<perlmod>), now clone an accessor method for each key in
-the %ClassData hash. Each of these methods is used to fetch or store
-values to the specific, named class attribute.
-
- for my $datum (keys %ClassData) {
- no strict "refs"; # to register new methods in package
- *$datum = sub {
- shift; # XXX: ignore calling class/object
- $ClassData{$datum} = shift if @_;
- return $ClassData{$datum};
- }
- }
-
-It's true that you could work out a solution employing an &AUTOLOAD
-method, but this approach is unlikely to prove satisfactory. Your
-function would have to distinguish between class attributes and object
-attributes; it could interfere with inheritance; and it would have to
-careful about DESTROY. Such complexity is uncalled for in most cases,
-and certainly in this one.
-
-You may wonder why we're rescinding strict refs for the loop. We're
-manipulating the package's symbol table to introduce new function names
-using symbolic references (indirect naming), which the strict pragma
-would otherwise forbid. Normally, symbolic references are a dodgy
-notion at best. This isn't just because they can be used accidentally
-when you aren't meaning to. It's also because for most uses
-to which beginning Perl programmers attempt to put symbolic references,
-we have much better approaches, like nested hashes or hashes of arrays.
-But there's nothing wrong with using symbolic references to manipulate
-something that is meaningful only from the perspective of the package
-symbol table, like method names or package variables. In other
-words, when you want to refer to the symbol table, use symbol references.
-
-Clustering all the class attributes in one place has several advantages.
-They're easy to spot, initialize, and change. The aggregation also
-makes them convenient to access externally, such as from a debugger
-or a persistence package. The only possible problem is that we don't
-automatically know the name of each class's class object, should it have
-one. This issue is addressed below in L<"The Eponymous Meta-Object">.
-
-=head2 Inheritance Concerns
-
-Suppose you have an instance of a derived class, and you access class
-data using an inherited method call. Should that end up referring
-to the base class's attributes, or to those in the derived class?
-How would it work in the earlier examples? The derived class inherits
-all the base class's methods, including those that access class attributes.
-But what package are the class attributes stored in?
-
-The answer is that, as written, class attributes are stored in the package into
-which those methods were compiled. When you invoke the &CData1 method
-on the name of the derived class or on one of that class's objects, the
-version shown above is still run, so you'll access $Some_Class::CData1--or
-in the method cloning version, C<$Some_Class::ClassData{CData1}>.
-
-Think of these class methods as executing in the context of their base
-class, not in that of their derived class. Sometimes this is exactly
-what you want. If Feline subclasses Carnivore, then the population of
-Carnivores in the world should go up when a new Feline is born.
-But what if you wanted to figure out how many Felines you have apart
-from Carnivores? The current approach doesn't support that.
-
-You'll have to decide on a case-by-case basis whether it makes any sense
-for class attributes to be package-relative. If you want it to be so,
-then stop ignoring the first argument to the function. Either it will
-be a package name if the method was invoked directly on a class name,
-or else it will be an object reference if the method was invoked on an
-object reference. In the latter case, the ref() function provides the
-class of that object.
-
- package Some_Class;
- sub CData1 {
- my $obclass = shift;
- my $class = ref($obclass) || $obclass;
- my $varname = $class . "::CData1";
- no strict "refs"; # to access package data symbolically
- $$varname = shift if @_;
- return $$varname;
- }
-
-And then do likewise for all other class attributes (such as CData2,
-etc.) that you wish to access as package variables in the invoking package
-instead of the compiling package as we had previously.
-
-Once again we temporarily disable the strict references ban, because
-otherwise we couldn't use the fully-qualified symbolic name for
-the package global. This is perfectly reasonable: since all package
-variables by definition live in a package, there's nothing wrong with
-accessing them via that package's symbol table. That's what it's there
-for (well, somewhat).
-
-What about just using a single hash for everything and then cloning
-methods? What would that look like? The only difference would be the
-closure used to produce new method entries for the class's symbol table.
-
- no strict "refs";
- *$datum = sub {
- my $obclass = shift;
- my $class = ref($obclass) || $obclass;
- my $varname = $class . "::ClassData";
- $varname->{$datum} = shift if @_;
- return $varname->{$datum};
- }
-
-=head2 The Eponymous Meta-Object
-
-It could be argued that the %ClassData hash in the previous example is
-neither the most imaginative nor the most intuitive of names. Is there
-something else that might make more sense, be more useful, or both?
-
-As it happens, yes, there is. For the "class meta-object", we'll use
-a package variable of the same name as the package itself. Within the
-scope of a package Some_Class declaration, we'll use the eponymously
-named hash %Some_Class as that class's meta-object. (Using an eponymously
-named hash is somewhat reminiscent of classes that name their constructors
-eponymously in the Python or C++ fashion. That is, class Some_Class would
-use &Some_Class::Some_Class as a constructor, probably even exporting that
-name as well. The StrNum class in Recipe 13.14 in I<The Perl Cookbook>
-does this, if you're looking for an example.)
-
-This predictable approach has many benefits, including having a well-known
-identifier to aid in debugging, transparent persistence,
-or checkpointing. It's also the obvious name for monadic classes and
-translucent attributes, discussed later.
-
-Here's an example of such a class. Notice how the name of the
-hash storing the meta-object is the same as the name of the package
-used to implement the class.
-
- package Some_Class;
- use strict;
-
- # create class meta-object using that most perfect of names
- our %Some_Class = ( # our() is new to perl5.6
- CData1 => "",
- CData2 => "",
- );
-
- # this accessor is calling-package-relative
- sub CData1 {
- my $obclass = shift;
- my $class = ref($obclass) || $obclass;
- no strict "refs"; # to access eponymous meta-object
- $class->{CData1} = shift if @_;
- return $class->{CData1};
- }
-
- # but this accessor is not
- sub CData2 {
- shift; # XXX: ignore calling class/object
- no strict "refs"; # to access eponymous meta-object
- __PACKAGE__ -> {CData2} = shift if @_;
- return __PACKAGE__ -> {CData2};
- }
-
-In the second accessor method, the __PACKAGE__ notation was used for
-two reasons. First, to avoid hardcoding the literal package name
-in the code in case we later want to change that name. Second, to
-clarify to the reader that what matters here is the package currently
-being compiled into, not the package of the invoking object or class.
-If the long sequence of non-alphabetic characters bothers you, you can
-always put the __PACKAGE__ in a variable first.
-
- sub CData2 {
- shift; # XXX: ignore calling class/object
- no strict "refs"; # to access eponymous meta-object
- my $class = __PACKAGE__;
- $class->{CData2} = shift if @_;
- return $class->{CData2};
- }
-
-Even though we're using symbolic references for good not evil, some
-folks tend to become unnerved when they see so many places with strict
-ref checking disabled. Given a symbolic reference, you can always
-produce a real reference (the reverse is not true, though). So we'll
-create a subroutine that does this conversion for us. If invoked as a
-function of no arguments, it returns a reference to the compiling class's
-eponymous hash. Invoked as a class method, it returns a reference to
-the eponymous hash of its caller. And when invoked as an object method,
-this function returns a reference to the eponymous hash for whatever
-class the object belongs to.
-
- package Some_Class;
- use strict;
-
- our %Some_Class = ( # our() is new to perl5.6
- CData1 => "",
- CData2 => "",
- );
-
- # tri-natured: function, class method, or object method
- sub _classobj {
- my $obclass = shift || __PACKAGE__;
- my $class = ref($obclass) || $obclass;
- no strict "refs"; # to convert sym ref to real one
- return \%$class;
- }
-
- for my $datum (keys %{ _classobj() } ) {
- # turn off strict refs so that we can
- # register a method in the symbol table
- no strict "refs";
- *$datum = sub {
- use strict "refs";
- my $self = shift->_classobj();
- $self->{$datum} = shift if @_;
- return $self->{$datum};
- }
- }
-
-=head2 Indirect References to Class Data
-
-A reasonably common strategy for handling class attributes is to store
-a reference to each package variable on the object itself. This is
-a strategy you've probably seen before, such as in L<perltoot> and
-L<perlbot>, but there may be variations in the example below that you
-haven't thought of before.
-
- package Some_Class;
- our($CData1, $CData2); # our() is new to perl5.6
-
- sub new {
- my $obclass = shift;
- return bless my $self = {
- ObData1 => "",
- ObData2 => "",
- CData1 => \$CData1,
- CData2 => \$CData2,
- } => (ref $obclass || $obclass);
- }
-
- sub ObData1 {
- my $self = shift;
- $self->{ObData1} = shift if @_;
- return $self->{ObData1};
- }
-
- sub ObData2 {
- my $self = shift;
- $self->{ObData2} = shift if @_;
- return $self->{ObData2};
- }
-
- sub CData1 {
- my $self = shift;
- my $dataref = ref $self
- ? $self->{CData1}
- : \$CData1;
- $$dataref = shift if @_;
- return $$dataref;
- }
-
- sub CData2 {
- my $self = shift;
- my $dataref = ref $self
- ? $self->{CData2}
- : \$CData2;
- $$dataref = shift if @_;
- return $$dataref;
- }
-
-As written above, a derived class will inherit these methods, which
-will consequently access package variables in the base class's package.
-This is not necessarily expected behavior in all circumstances. Here's an
-example that uses a variable meta-object, taking care to access the
-proper package's data.
-
- package Some_Class;
- use strict;
-
- our %Some_Class = ( # our() is new to perl5.6
- CData1 => "",
- CData2 => "",
- );
-
- sub _classobj {
- my $self = shift;
- my $class = ref($self) || $self;
- no strict "refs";
- # get (hard) ref to eponymous meta-object
- return \%$class;
- }
-
- sub new {
- my $obclass = shift;
- my $classobj = $obclass->_classobj();
- bless my $self = {
- ObData1 => "",
- ObData2 => "",
- CData1 => \$classobj->{CData1},
- CData2 => \$classobj->{CData2},
- } => (ref $obclass || $obclass);
- return $self;
- }
-
- sub ObData1 {
- my $self = shift;
- $self->{ObData1} = shift if @_;
- return $self->{ObData1};
- }
-
- sub ObData2 {
- my $self = shift;
- $self->{ObData2} = shift if @_;
- return $self->{ObData2};
- }
-
- sub CData1 {
- my $self = shift;
- $self = $self->_classobj() unless ref $self;
- my $dataref = $self->{CData1};
- $$dataref = shift if @_;
- return $$dataref;
- }
-
- sub CData2 {
- my $self = shift;
- $self = $self->_classobj() unless ref $self;
- my $dataref = $self->{CData2};
- $$dataref = shift if @_;
- return $$dataref;
- }
-
-Not only are we now strict refs clean, using an eponymous meta-object
-seems to make the code cleaner. Unlike the previous version, this one
-does something interesting in the face of inheritance: it accesses the
-class meta-object in the invoking class instead of the one into which
-the method was initially compiled.
-
-You can easily access data in the class meta-object, making
-it easy to dump the complete class state using an external mechanism such
-as when debugging or implementing a persistent class. This works because
-the class meta-object is a package variable, has a well-known name, and
-clusters all its data together. (Transparent persistence
-is not always feasible, but it's certainly an appealing idea.)
-
-There's still no check that object accessor methods have not been
-invoked on a class name. If strict ref checking is enabled, you'd
-blow up. If not, then you get the eponymous meta-object. What you do
-with--or about--this is up to you. The next two sections demonstrate
-innovative uses for this powerful feature.
-
-=head2 Monadic Classes
-
-Some of the standard modules shipped with Perl provide class interfaces
-without any attribute methods whatsoever. The most commonly used module
-not numbered amongst the pragmata, the Exporter module, is a class with
-neither constructors nor attributes. Its job is simply to provide a
-standard interface for modules wishing to export part of their namespace
-into that of their caller. Modules use the Exporter's &import method by
-setting their inheritance list in their package's @ISA array to mention
-"Exporter". But class Exporter provides no constructor, so you can't
-have several instances of the class. In fact, you can't have any--it
-just doesn't make any sense. All you get is its methods. Its interface
-contains no statefulness, so state data is wholly superfluous.
-
-Another sort of class that pops up from time to time is one that supports
-a unique instance. Such classes are called I<monadic classes>, or less
-formally, I<singletons> or I<highlander classes>.
-
-If a class is monadic, where do you store its state, that is,
-its attributes? How do you make sure that there's never more than
-one instance? While you could merely use a slew of package variables,
-it's a lot cleaner to use the eponymously named hash. Here's a complete
-example of a monadic class:
-
- package Cosmos;
- %Cosmos = ();
-
- # accessor method for "name" attribute
- sub name {
- my $self = shift;
- $self->{name} = shift if @_;
- return $self->{name};
- }
-
- # read-only accessor method for "birthday" attribute
- sub birthday {
- my $self = shift;
- die "can't reset birthday" if @_; # XXX: croak() is better
- return $self->{birthday};
- }
-
- # accessor method for "stars" attribute
- sub stars {
- my $self = shift;
- $self->{stars} = shift if @_;
- return $self->{stars};
- }
-
- # oh my - one of our stars just went out!
- sub supernova {
- my $self = shift;
- my $count = $self->stars();
- $self->stars($count - 1) if $count > 0;
- }
-
- # constructor/initializer method - fix by reboot
- sub bigbang {
- my $self = shift;
- %$self = (
- name => "the world according to tchrist",
- birthday => time(),
- stars => 0,
- );
- return $self; # yes, it's probably a class. SURPRISE!
- }
-
- # After the class is compiled, but before any use or require
- # returns, we start off the universe with a bang.
- __PACKAGE__ -> bigbang();
-
-Hold on, that doesn't look like anything special. Those attribute
-accessors look no different than they would if this were a regular class
-instead of a monadic one. The crux of the matter is there's nothing
-that says that $self must hold a reference to a blessed object. It merely
-has to be something you can invoke methods on. Here the package name
-itself, Cosmos, works as an object. Look at the &supernova method. Is that
-a class method or an object method? The answer is that static analysis
-cannot reveal the answer. Perl doesn't care, and neither should you.
-In the three attribute methods, C<%$self> is really accessing the %Cosmos
-package variable.
-
-If like Stephen Hawking, you posit the existence of multiple, sequential,
-and unrelated universes, then you can invoke the &bigbang method yourself
-at any time to start everything all over again. You might think of
-&bigbang as more of an initializer than a constructor, since the function
-doesn't allocate new memory; it only initializes what's already there.
-But like any other constructor, it does return a scalar value to use
-for later method invocations.
-
-Imagine that some day in the future, you decide that one universe just
-isn't enough. You could write a new class from scratch, but you already
-have an existing class that does what you want--except that it's monadic,
-and you want more than just one cosmos.
-
-That's what code reuse via subclassing is all about. Look how short
-the new code is:
-
- package Multiverse;
- use Cosmos;
- @ISA = qw(Cosmos);
-
- sub new {
- my $protoverse = shift;
- my $class = ref($protoverse) || $protoverse;
- my $self = {};
- return bless($self, $class)->bigbang();
- }
- 1;
-
-Because we were careful to be good little creators when we designed our
-Cosmos class, we can now reuse it without touching a single line of code
-when it comes time to write our Multiverse class. The same code that
-worked when invoked as a class method continues to work perfectly well
-when invoked against separate instances of a derived class.
-
-The astonishing thing about the Cosmos class above is that the value
-returned by the &bigbang "constructor" is not a reference to a blessed
-object at all. It's just the class's own name. A class name is, for
-virtually all intents and purposes, a perfectly acceptable object.
-It has state, behavior, and identity, the three crucial components
-of an object system. It even manifests inheritance, polymorphism,
-and encapsulation. And what more can you ask of an object?
-
-To understand object orientation in Perl, it's important to recognize the
-unification of what other programming languages might think of as class
-methods and object methods into just plain methods. "Class methods"
-and "object methods" are distinct only in the compartmentalizing mind
-of the Perl programmer, not in the Perl language itself.
-
-Along those same lines, a constructor is nothing special either, which
-is one reason why Perl has no pre-ordained name for them. "Constructor"
-is just an informal term loosely used to describe a method that returns
-a scalar value that you can make further method calls against. So long
-as it's either a class name or an object reference, that's good enough.
-It doesn't even have to be a reference to a brand new object.
-
-You can have as many--or as few--constructors as you want, and you can
-name them whatever you care to. Blindly and obediently using new()
-for each and every constructor you ever write is to speak Perl with
-such a severe C++ accent that you do a disservice to both languages.
-There's no reason to insist that each class have but one constructor,
-or that a constructor be named new(), or that a constructor be
-used solely as a class method and not an object method.
-
-The next section shows how useful it can be to further distance ourselves
-from any formal distinction between class method calls and object method
-calls, both in constructors and in accessor methods.
-
-=head2 Translucent Attributes
-
-A package's eponymous hash can be used for more than just containing
-per-class, global state data. It can also serve as a sort of template
-containing default settings for object attributes. These default
-settings can then be used in constructors for initialization of a
-particular object. The class's eponymous hash can also be used to
-implement I<translucent attributes>. A translucent attribute is one
-that has a class-wide default. Each object can set its own value for the
-attribute, in which case C<< $object->attribute() >> returns that value.
-But if no value has been set, then C<< $object->attribute() >> returns
-the class-wide default.
-
-We'll apply something of a copy-on-write approach to these translucent
-attributes. If you're just fetching values from them, you get
-translucency. But if you store a new value to them, that new value is
-set on the current object. On the other hand, if you use the class as
-an object and store the attribute value directly on the class, then the
-meta-object's value changes, and later fetch operations on objects with
-uninitialized values for those attributes will retrieve the meta-object's
-new values. Objects with their own initialized values, however, won't
-see any change.
-
-Let's look at some concrete examples of using these properties before we
-show how to implement them. Suppose that a class named Some_Class
-had a translucent data attribute called "color". First you set the color
-in the meta-object, then you create three objects using a constructor
-that happens to be named &spawn.
-
- use Vermin;
- Vermin->color("vermilion");
-
- $ob1 = Vermin->spawn(); # so that's where Jedi come from
- $ob2 = Vermin->spawn();
- $ob3 = Vermin->spawn();
-
- print $obj3->color(); # prints "vermilion"
-
-Each of these objects' colors is now "vermilion", because that's the
-meta-object's value for that attribute, and these objects do not have
-individual color values set.
-
-Changing the attribute on one object has no effect on other objects
-previously created.
-
- $ob3->color("chartreuse");
- print $ob3->color(); # prints "chartreuse"
- print $ob1->color(); # prints "vermilion", translucently
-
-If you now use $ob3 to spawn off another object, the new object will
-take the color its parent held, which now happens to be "chartreuse".
-That's because the constructor uses the invoking object as its template
-for initializing attributes. When that invoking object is the
-class name, the object used as a template is the eponymous meta-object.
-When the invoking object is a reference to an instantiated object, the
-&spawn constructor uses that existing object as a template.
-
- $ob4 = $ob3->spawn(); # $ob3 now template, not %Vermin
- print $ob4->color(); # prints "chartreuse"
-
-Any actual values set on the template object will be copied to the
-new object. But attributes undefined in the template object, being
-translucent, will remain undefined and consequently translucent in the
-new one as well.
-
-Now let's change the color attribute on the entire class:
-
- Vermin->color("azure");
- print $ob1->color(); # prints "azure"
- print $ob2->color(); # prints "azure"
- print $ob3->color(); # prints "chartreuse"
- print $ob4->color(); # prints "chartreuse"
-
-That color change took effect only in the first pair of objects, which
-were still translucently accessing the meta-object's values. The second
-pair had per-object initialized colors, and so didn't change.
-
-One important question remains. Changes to the meta-object are reflected
-in translucent attributes in the entire class, but what about
-changes to discrete objects? If you change the color of $ob3, does the
-value of $ob4 see that change? Or vice-versa. If you change the color
-of $ob4, does then the value of $ob3 shift?
-
- $ob3->color("amethyst");
- print $ob3->color(); # prints "amethyst"
- print $ob4->color(); # hmm: "chartreuse" or "amethyst"?
-
-While one could argue that in certain rare cases it should, let's not
-do that. Good taste aside, we want the answer to the question posed in
-the comment above to be "chartreuse", not "amethyst". So we'll treat
-these attributes similar to the way process attributes like environment
-variables, user and group IDs, or the current working directory are
-treated across a fork(). You can change only yourself, but you will see
-those changes reflected in your unspawned children. Changes to one object
-will propagate neither up to the parent nor down to any existing child objects.
-Those objects made later, however, will see the changes.
-
-If you have an object with an actual attribute value, and you want to
-make that object's attribute value translucent again, what do you do?
-Let's design the class so that when you invoke an accessor method with
-C<undef> as its argument, that attribute returns to translucency.
-
- $ob4->color(undef); # back to "azure"
-
-Here's a complete implementation of Vermin as described above.
-
- package Vermin;
-
- # here's the class meta-object, eponymously named.
- # it holds all class attributes, and also all instance attributes
- # so the latter can be used for both initialization
- # and translucency.
-
- our %Vermin = ( # our() is new to perl5.6
- PopCount => 0, # capital for class attributes
- color => "beige", # small for instance attributes
- );
-
- # constructor method
- # invoked as class method or object method
- sub spawn {
- my $obclass = shift;
- my $class = ref($obclass) || $obclass;
- my $self = {};
- bless($self, $class);
- $class->{PopCount}++;
- # init fields from invoking object, or omit if
- # invoking object is the class to provide translucency
- %$self = %$obclass if ref $obclass;
- return $self;
- }
-
- # translucent accessor for "color" attribute
- # invoked as class method or object method
- sub color {
- my $self = shift;
- my $class = ref($self) || $self;
-
- # handle class invocation
- unless (ref $self) {
- $class->{color} = shift if @_;
- return $class->{color}
- }
-
- # handle object invocation
- $self->{color} = shift if @_;
- if (defined $self->{color}) { # not exists!
- return $self->{color};
- } else {
- return $class->{color};
- }
- }
-
- # accessor for "PopCount" class attribute
- # invoked as class method or object method
- # but uses object solely to locate meta-object
- sub population {
- my $obclass = shift;
- my $class = ref($obclass) || $obclass;
- return $class->{PopCount};
- }
-
- # instance destructor
- # invoked only as object method
- sub DESTROY {
- my $self = shift;
- my $class = ref $self;
- $class->{PopCount}--;
- }
-
-Here are a couple of helper methods that might be convenient. They aren't
-accessor methods at all. They're used to detect accessibility of data
-attributes. The &is_translucent method determines whether a particular
-object attribute is coming from the meta-object. The &has_attribute
-method detects whether a class implements a particular property at all.
-It could also be used to distinguish undefined properties from non-existent
-ones.
-
- # detect whether an object attribute is translucent
- # (typically?) invoked only as object method
- sub is_translucent {
- my($self, $attr) = @_;
- return !defined $self->{$attr};
- }
-
- # test for presence of attribute in class
- # invoked as class method or object method
- sub has_attribute {
- my($self, $attr) = @_;
- my $class = ref($self) || $self;
- return exists $class->{$attr};
- }
-
-If you prefer to install your accessors more generically, you can make
-use of the upper-case versus lower-case convention to register into the
-package appropriate methods cloned from generic closures.
-
- for my $datum (keys %{ +__PACKAGE__ }) {
- *$datum = ($datum =~ /^[A-Z]/)
- ? sub { # install class accessor
- my $obclass = shift;
- my $class = ref($obclass) || $obclass;
- return $class->{$datum};
- }
- : sub { # install translucent accessor
- my $self = shift;
- my $class = ref($self) || $self;
- unless (ref $self) {
- $class->{$datum} = shift if @_;
- return $class->{$datum}
- }
- $self->{$datum} = shift if @_;
- return defined $self->{$datum}
- ? $self -> {$datum}
- : $class -> {$datum}
- }
- }
-
-Translations of this closure-based approach into C++, Java, and Python
-have been left as exercises for the reader. Be sure to send us mail as
-soon as you're done.
-
-=head1 Class Data as Lexical Variables
-
-=head2 Privacy and Responsibility
-
-Unlike conventions used by some Perl programmers, in the previous
-examples, we didn't prefix the package variables used for class attributes
-with an underscore, nor did we do so for the names of the hash keys used
-for instance attributes. You don't need little markers on data names to
-suggest nominal privacy on attribute variables or hash keys, because these
-are B<already> notionally private! Outsiders have no business whatsoever
-playing with anything within a class save through the mediated access of
-its documented interface; in other words, through method invocations.
-And not even through just any method, either. Methods that begin with
-an underscore are traditionally considered off-limits outside the class.
-If outsiders skip the documented method interface to poke around the
-internals of your class and end up breaking something, that's not your
-fault--it's theirs.
-
-Perl believes in individual responsibility rather than mandated control.
-Perl respects you enough to let you choose your own preferred level of
-pain, or of pleasure. Perl believes that you are creative, intelligent,
-and capable of making your own decisions--and fully expects you to
-take complete responsibility for your own actions. In a perfect world,
-these admonitions alone would suffice, and everyone would be intelligent,
-responsible, happy, and creative. And careful. One probably shouldn't
-forget careful, and that's a good bit harder to expect. Even Einstein
-would take wrong turns by accident and end up lost in the wrong part
-of town.
-
-Some folks get the heebie-jeebies when they see package variables
-hanging out there for anyone to reach over and alter them. Some folks
-live in constant fear that someone somewhere might do something wicked.
-The solution to that problem is simply to fire the wicked, of course.
-But unfortunately, it's not as simple as all that. These cautious
-types are also afraid that they or others will do something not so
-much wicked as careless, whether by accident or out of desperation.
-If we fire everyone who ever gets careless, pretty soon there won't be
-anybody left to get any work done.
-
-Whether it's needless paranoia or sensible caution, this uneasiness can
-be a problem for some people. We can take the edge off their discomfort
-by providing the option of storing class attributes as lexical variables
-instead of as package variables. The my() operator is the source of
-all privacy in Perl, and it is a powerful form of privacy indeed.
-
-It is widely perceived, and indeed has often been written, that Perl
-provides no data hiding, that it affords the class designer no privacy
-nor isolation, merely a rag-tag assortment of weak and unenforceable
-social conventions instead. This perception is demonstrably false and
-easily disproven. In the next section, we show how to implement forms
-of privacy that are far stronger than those provided in nearly any
-other object-oriented language.
-
-=head2 File-Scoped Lexicals
-
-A lexical variable is visible only through the end of its static scope.
-That means that the only code able to access that variable is code
-residing textually below the my() operator through the end of its block
-if it has one, or through the end of the current file if it doesn't.
-
-Starting again with our simplest example given at the start of this
-document, we replace our() variables with my() versions.
-
- package Some_Class;
- my($CData1, $CData2); # file scope, not in any package
- sub CData1 {
- shift; # XXX: ignore calling class/object
- $CData1 = shift if @_;
- return $CData1;
- }
- sub CData2 {
- shift; # XXX: ignore calling class/object
- $CData2 = shift if @_;
- return $CData2;
- }
-
-So much for that old $Some_Class::CData1 package variable and its brethren!
-Those are gone now, replaced with lexicals. No one outside the
-scope can reach in and alter the class state without resorting to the
-documented interface. Not even subclasses or superclasses of
-this one have unmediated access to $CData1. They have to invoke the &CData1
-method against Some_Class or an instance thereof, just like anybody else.
-
-To be scrupulously honest, that last statement assumes you haven't packed
-several classes together into the same file scope, nor strewn your class
-implementation across several different files. Accessibility of those
-variables is based uniquely on the static file scope. It has nothing to
-do with the package. That means that code in a different file but
-the same package (class) could not access those variables, yet code in the
-same file but a different package (class) could. There are sound reasons
-why we usually suggest a one-to-one mapping between files and packages
-and modules and classes. You don't have to stick to this suggestion if
-you really know what you're doing, but you're apt to confuse yourself
-otherwise, especially at first.
-
-If you'd like to aggregate your class attributes into one lexically scoped,
-composite structure, you're perfectly free to do so.
-
- package Some_Class;
- my %ClassData = (
- CData1 => "",
- CData2 => "",
- );
- sub CData1 {
- shift; # XXX: ignore calling class/object
- $ClassData{CData1} = shift if @_;
- return $ClassData{CData1};
- }
- sub CData2 {
- shift; # XXX: ignore calling class/object
- $ClassData{CData2} = shift if @_;
- return $ClassData{CData2};
- }
-
-To make this more scalable as other class attributes are added, we can
-again register closures into the package symbol table to create accessor
-methods for them.
-
- package Some_Class;
- my %ClassData = (
- CData1 => "",
- CData2 => "",
- );
- for my $datum (keys %ClassData) {
- no strict "refs";
- *$datum = sub {
- shift; # XXX: ignore calling class/object
- $ClassData{$datum} = shift if @_;
- return $ClassData{$datum};
- };
- }
-
-Requiring even your own class to use accessor methods like anybody else is
-probably a good thing. But demanding and expecting that everyone else,
-be they subclass or superclass, friend or foe, will all come to your
-object through mediation is more than just a good idea. It's absolutely
-critical to the model. Let there be in your mind no such thing as
-"public" data, nor even "protected" data, which is a seductive but
-ultimately destructive notion. Both will come back to bite at you.
-That's because as soon as you take that first step out of the solid
-position in which all state is considered completely private, save from the
-perspective of its own accessor methods, you have violated the envelope.
-And, having pierced that encapsulating envelope, you shall doubtless
-someday pay the price when future changes in the implementation break
-unrelated code. Considering that avoiding this infelicitous outcome was
-precisely why you consented to suffer the slings and arrows of obsequious
-abstraction by turning to object orientation in the first place, such
-breakage seems unfortunate in the extreme.
-
-=head2 More Inheritance Concerns
-
-Suppose that Some_Class were used as a base class from which to derive
-Another_Class. If you invoke a &CData method on the derived class or
-on an object of that class, what do you get? Would the derived class
-have its own state, or would it piggyback on its base class's versions
-of the class attributes?
-
-The answer is that under the scheme outlined above, the derived class
-would B<not> have its own state data. As before, whether you consider
-this a good thing or a bad one depends on the semantics of the classes
-involved.
-
-The cleanest, sanest, simplest way to address per-class state in a
-lexical is for the derived class to override its base class's version
-of the method that accesses the class attributes. Since the actual method
-called is the one in the object's derived class if this exists, you
-automatically get per-class state this way. Any urge to provide an
-unadvertised method to sneak out a reference to the %ClassData hash
-should be strenuously resisted.
-
-As with any other overridden method, the implementation in the
-derived class always has the option of invoking its base class's
-version of the method in addition to its own. Here's an example:
-
- package Another_Class;
- @ISA = qw(Some_Class);
-
- my %ClassData = (
- CData1 => "",
- );
-
- sub CData1 {
- my($self, $newvalue) = @_;
- if (@_ > 1) {
- # set locally first
- $ClassData{CData1} = $newvalue;
-
- # then pass the buck up to the first
- # overridden version, if there is one
- if ($self->can("SUPER::CData1")) {
- $self->SUPER::CData1($newvalue);
- }
- }
- return $ClassData{CData1};
- }
-
-Those dabbling in multiple inheritance might be concerned
-about there being more than one override.
-
- for my $parent (@ISA) {
- my $methname = $parent . "::CData1";
- if ($self->can($methname)) {
- $self->$methname($newvalue);
- }
- }
-
-Because the &UNIVERSAL::can method returns a reference
-to the function directly, you can use this directly
-for a significant performance improvement:
-
- for my $parent (@ISA) {
- if (my $coderef = $self->can($parent . "::CData1")) {
- $self->$coderef($newvalue);
- }
- }
-
-If you override C<UNIVERSAL::can> in your own classes, be sure to return the
-reference appropriately.
-
-=head2 Locking the Door and Throwing Away the Key
-
-As currently implemented, any code within the same scope as the
-file-scoped lexical %ClassData can alter that hash directly. Is that
-ok? Is it acceptable or even desirable to allow other parts of the
-implementation of this class to access class attributes directly?
-
-That depends on how careful you want to be. Think back to the Cosmos
-class. If the &supernova method had directly altered $Cosmos::Stars or
-C<$Cosmos::Cosmos{stars}>, then we wouldn't have been able to reuse the
-class when it came to inventing a Multiverse. So letting even the class
-itself access its own class attributes without the mediating intervention of
-properly designed accessor methods is probably not a good idea after all.
-
-Restricting access to class attributes from the class itself is usually
-not enforceable even in strongly object-oriented languages. But in Perl,
-you can.
-
-Here's one way:
-
- package Some_Class;
-
- { # scope for hiding $CData1
- my $CData1;
- sub CData1 {
- shift; # XXX: unused
- $CData1 = shift if @_;
- return $CData1;
- }
- }
-
- { # scope for hiding $CData2
- my $CData2;
- sub CData2 {
- shift; # XXX: unused
- $CData2 = shift if @_;
- return $CData2;
- }
- }
-
-No one--absolutely no one--is allowed to read or write the class
-attributes without the mediation of the managing accessor method, since
-only that method has access to the lexical variable it's managing.
-This use of mediated access to class attributes is a form of privacy far
-stronger than most OO languages provide.
-
-The repetition of code used to create per-datum accessor methods chafes
-at our Laziness, so we'll again use closures to create similar
-methods.
-
- package Some_Class;
-
- { # scope for ultra-private meta-object for class attributes
- my %ClassData = (
- CData1 => "",
- CData2 => "",
- );
-
- for my $datum (keys %ClassData ) {
- no strict "refs";
- *$datum = sub {
- use strict "refs";
- my ($self, $newvalue) = @_;
- $ClassData{$datum} = $newvalue if @_ > 1;
- return $ClassData{$datum};
- }
- }
-
- }
-
-The closure above can be modified to take inheritance into account using
-the &UNIVERSAL::can method and SUPER as shown previously.
-
-=head2 Translucency Revisited
-
-The Vermin class demonstrates translucency using a package variable,
-eponymously named %Vermin, as its meta-object. If you prefer to
-use absolutely no package variables beyond those necessary to appease
-inheritance or possibly the Exporter, this strategy is closed to you.
-That's too bad, because translucent attributes are an appealing
-technique, so it would be valuable to devise an implementation using
-only lexicals.
-
-There's a second reason why you might wish to avoid the eponymous
-package hash. If you use class names with double-colons in them, you
-would end up poking around somewhere you might not have meant to poke.
-
- package Vermin;
- $class = "Vermin";
- $class->{PopCount}++;
- # accesses $Vermin::Vermin{PopCount}
-
- package Vermin::Noxious;
- $class = "Vermin::Noxious";
- $class->{PopCount}++;
- # accesses $Vermin::Noxious{PopCount}
-
-In the first case, because the class name had no double-colons, we got
-the hash in the current package. But in the second case, instead of
-getting some hash in the current package, we got the hash %Noxious in
-the Vermin package. (The noxious vermin just invaded another package and
-sprayed their data around it. :-) Perl doesn't support relative packages
-in its naming conventions, so any double-colons trigger a fully-qualified
-lookup instead of just looking in the current package.
-
-In practice, it is unlikely that the Vermin class had an existing
-package variable named %Noxious that you just blew away. If you're
-still mistrustful, you could always stake out your own territory
-where you know the rules, such as using Eponymous::Vermin::Noxious or
-Hieronymus::Vermin::Boschious or Leave_Me_Alone::Vermin::Noxious as class
-names instead. Sure, it's in theory possible that someone else has
-a class named Eponymous::Vermin with its own %Noxious hash, but this
-kind of thing is always true. There's no arbiter of package names.
-It's always the case that globals like @Cwd::ISA would collide if more
-than one class uses the same Cwd package.
-
-If this still leaves you with an uncomfortable twinge of paranoia,
-we have another solution for you. There's nothing that says that you
-have to have a package variable to hold a class meta-object, either for
-monadic classes or for translucent attributes. Just code up the methods
-so that they access a lexical instead.
-
-Here's another implementation of the Vermin class with semantics identical
-to those given previously, but this time using no package variables.
-
- package Vermin;
-
-
- # Here's the class meta-object, eponymously named.
- # It holds all class data, and also all instance data
- # so the latter can be used for both initialization
- # and translucency. it's a template.
- my %ClassData = (
- PopCount => 0, # capital for class attributes
- color => "beige", # small for instance attributes
- );
-
- # constructor method
- # invoked as class method or object method
- sub spawn {
- my $obclass = shift;
- my $class = ref($obclass) || $obclass;
- my $self = {};
- bless($self, $class);
- $ClassData{PopCount}++;
- # init fields from invoking object, or omit if
- # invoking object is the class to provide translucency
- %$self = %$obclass if ref $obclass;
- return $self;
- }
-
- # translucent accessor for "color" attribute
- # invoked as class method or object method
- sub color {
- my $self = shift;
-
- # handle class invocation
- unless (ref $self) {
- $ClassData{color} = shift if @_;
- return $ClassData{color}
- }
-
- # handle object invocation
- $self->{color} = shift if @_;
- if (defined $self->{color}) { # not exists!
- return $self->{color};
- } else {
- return $ClassData{color};
- }
- }
-
- # class attribute accessor for "PopCount" attribute
- # invoked as class method or object method
- sub population {
- return $ClassData{PopCount};
- }
-
- # instance destructor; invoked only as object method
- sub DESTROY {
- $ClassData{PopCount}--;
- }
-
- # detect whether an object attribute is translucent
- # (typically?) invoked only as object method
- sub is_translucent {
- my($self, $attr) = @_;
- $self = \%ClassData if !ref $self;
- return !defined $self->{$attr};
- }
-
- # test for presence of attribute in class
- # invoked as class method or object method
- sub has_attribute {
- my($self, $attr) = @_;
- return exists $ClassData{$attr};
- }
-
-=head1 NOTES
-
-Inheritance is a powerful but subtle device, best used only after careful
-forethought and design. Aggregation instead of inheritance is often a
-better approach.
-
-You can't use file-scoped lexicals in conjunction with the SelfLoader
-or the AutoLoader, because they alter the lexical scope in which the
-module's methods wind up getting compiled.
-
-The usual mealy-mouthed package-munging doubtless applies to setting
-up names of object attributes. For example, C<< $self->{ObData1} >>
-should probably be C<< $self->{ __PACKAGE__ . "_ObData1" } >>, but that
-would just confuse the examples.
-
-=head1 SEE ALSO
-
-L<perltoot>, L<perlobj>, L<perlmod>, and L<perlbot>.
-
-The Tie::SecureHash and Class::Data::Inheritable modules from CPAN are
-worth checking out.
-
-=head1 AUTHOR AND COPYRIGHT
-
-Copyright (c) 1999 Tom Christiansen.
-All rights reserved.
-
-This documentation is free; you can redistribute it and/or modify it
-under the same terms as Perl itself.
-
-Irrespective of its distribution, all code examples in this file
-are hereby placed into the public domain. You are permitted and
-encouraged to use this code in your own programs for fun
-or for profit as you see fit. A simple comment in the code giving
-credit would be courteous but is not required.
-
-=head1 ACKNOWLEDGEMENTS
-
-Russ Allbery, Jon Orwant, Randy Ray, Larry Rosler, Nat Torkington,
-and Stephen Warren all contributed suggestions and corrections to this
-piece. Thanks especially to Damian Conway for his ideas and feedback,
-and without whose indirect prodding I might never have taken the time
-to show others how much Perl has to offer in the way of objects once
-you start thinking outside the tiny little box that today's "popular"
-object-oriented languages enforce.
-
-=head1 HISTORY
-
-Last edit: Sun Feb 4 20:50:28 EST 2001
+++ /dev/null
-=head1 NAME
-
-perltoot - Tom's object-oriented tutorial for perl
-
-=head1 DESCRIPTION
-
-Object-oriented programming is a big seller these days. Some managers
-would rather have objects than sliced bread. Why is that? What's so
-special about an object? Just what I<is> an object anyway?
-
-An object is nothing but a way of tucking away complex behaviours into
-a neat little easy-to-use bundle. (This is what professors call
-abstraction.) Smart people who have nothing to do but sit around for
-weeks on end figuring out really hard problems make these nifty
-objects that even regular people can use. (This is what professors call
-software reuse.) Users (well, programmers) can play with this little
-bundle all they want, but they aren't to open it up and mess with the
-insides. Just like an expensive piece of hardware, the contract says
-that you void the warranty if you muck with the cover. So don't do that.
-
-The heart of objects is the class, a protected little private namespace
-full of data and functions. A class is a set of related routines that
-addresses some problem area. You can think of it as a user-defined type.
-The Perl package mechanism, also used for more traditional modules,
-is used for class modules as well. Objects "live" in a class, meaning
-that they belong to some package.
-
-More often than not, the class provides the user with little bundles.
-These bundles are objects. They know whose class they belong to,
-and how to behave. Users ask the class to do something, like "give
-me an object." Or they can ask one of these objects to do something.
-Asking a class to do something for you is calling a I<class method>.
-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
-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
-fundamental type? The answer to the first question is easy. An object
-is different from any other data type in Perl in one and only one way:
-you may dereference it using not merely string or numeric subscripts
-as with simple arrays and hashes, but with named subroutine calls.
-In a word, with I<methods>.
-
-The answer to the second question is that it's a reference, and not just
-any reference, mind you, but one whose referent has been I<bless>()ed
-into a particular class (read: package). What kind of reference? Well,
-the answer to that one is a bit less concrete. That's because in Perl
-the designer of the class can employ any sort of reference they'd like
-as the underlying intrinsic data type. It could be a scalar, an array,
-or a hash reference. It could even be a code reference. But because
-of its inherent flexibility, an object is usually a hash reference.
-
-=head1 Creating a Class
-
-Before you create a class, you need to decide what to name it. That's
-because the class (package) name governs the name of the file used to
-house it, just as with regular modules. Then, that class (package)
-should provide one or more ways to generate objects. Finally, it should
-provide mechanisms to allow users of its objects to indirectly manipulate
-these objects from a distance.
-
-For example, let's make a simple Person class module. It gets stored in
-the file Person.pm. If it were called a Happy::Person class, it would
-be stored in the file Happy/Person.pm, and its package would become
-Happy::Person instead of just Person. (On a personal computer not
-running Unix or Plan 9, but something like Mac OS or VMS, the directory
-separator may be different, but the principle is the same.) Do not assume
-any formal relationship between modules based on their directory names.
-This is merely a grouping convenience, and has no effect on inheritance,
-variable accessibility, or anything else.
-
-For this module we aren't going to use Exporter, because we're
-a well-behaved class module that doesn't export anything at all.
-In order to manufacture objects, a class needs to have a I<constructor
-method>. A constructor gives you back not just a regular data type,
-but a brand-new object in that class. This magic is taken care of by
-the bless() function, whose sole purpose is to enable its referent to
-be used as an object. Remember: being an object really means nothing
-more than that methods may now be called against it.
-
-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
-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 is 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.
-
-If you were just doing a simple
-struct-like emulation, you would likely go about it something like this:
-
- $rec = {
- name => "Jason",
- age => 23,
- peers => [ "Norbert", "Rhys", "Phineas"],
- };
-
-If you felt like it, you could add a bit of visual distinction
-by up-casing the hash keys:
-
- $rec = {
- NAME => "Jason",
- AGE => 23,
- PEERS => [ "Norbert", "Rhys", "Phineas"],
- };
-
-And so you could get at C<< $rec->{NAME} >> to find "Jason", or
-C<< @{ $rec->{PEERS} } >> to get at "Norbert", "Rhys", and "Phineas".
-(Have you ever noticed how many 23-year-old programmers seem to
-be named "Jason" these days? :-)
-
-This same model is often used for classes, although it is not considered
-the pinnacle of programming propriety for folks from outside the
-class to come waltzing into an object, brazenly accessing its data
-members directly. Generally speaking, an object should be considered
-an opaque cookie that you use I<object methods> to access. Visually,
-methods look like you're dereffing a reference using a function name
-instead of brackets or braces.
-
-=head2 Class Interface
-
-Some languages provide a formal syntactic interface to a class's methods,
-but Perl does not. It relies on you to read the documentation of each
-class. If you try to call an undefined method on an object, Perl won't
-complain, but the program will trigger an exception while it's running.
-Likewise, if you call a method expecting a prime number as its argument
-with a non-prime 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 your Person class,
-someone who has read the docs that explain the prescribed
-interface. Here's how they might use the Person class:
-
- use Person;
-
- $him = Person->new();
- $him->name("Jason");
- $him->age(23);
- $him->peers( "Norbert", "Rhys", "Phineas" );
-
- push @All_Recs, $him; # save object in array for later
-
- printf "%s is %d years old.\n", $him->name, $him->age;
- print "His peers are: ", join(", ", $him->peers), "\n";
-
- printf "Last rec's name is %s\n", $All_Recs[-1]->name;
-
-As you can see, the user of the class doesn't know (or at least, has no
-business paying attention to the fact) that the object has one particular
-implementation or another. The interface to the class and its objects
-is exclusively via methods, and that's all the user of the class should
-ever play with.
-
-=head2 Constructors and Instance Methods
-
-Still, I<someone> has to know what's in the object. And that someone is
-the class. It implements methods that the programmer uses to access
-the object. Here's how to implement the Person class using the standard
-hash-ref-as-an-object idiom. We'll make a class method called new() to
-act as the constructor, and three object methods called name(), age(), and
-peers() to get at per-object data hidden away in our anonymous hash.
-
- package Person;
- use strict;
-
- ##################################################
- ## the object constructor (simplistic version) ##
- ##################################################
- sub new {
- my $self = {};
- $self->{NAME} = undef;
- $self->{AGE} = undef;
- $self->{PEERS} = [];
- bless($self); # but see below
- return $self;
- }
-
- ##############################################
- ## methods to access per-object data ##
- ## ##
- ## With args, they set the value. Without ##
- ## any, they only retrieve it/them. ##
- ##############################################
-
- sub name {
- my $self = shift;
- if (@_) { $self->{NAME} = shift }
- return $self->{NAME};
- }
-
- sub age {
- my $self = shift;
- if (@_) { $self->{AGE} = shift }
- return $self->{AGE};
- }
-
- sub peers {
- my $self = shift;
- if (@_) { @{ $self->{PEERS} } = @_ }
- return @{ $self->{PEERS} };
- }
-
- 1; # so the require or use succeeds
-
-We've created three methods to access an object's data, name(), age(),
-and peers(). These are all substantially similar. If called with an
-argument, they set the appropriate field; otherwise they return the
-value held by that field, meaning the value of that hash key.
-
-=head2 Planning for the Future: Better Constructors
-
-Even though at this point you may not even know what it means, someday
-you're going to worry about inheritance. (You can safely ignore this
-for now and worry about it later if you'd like.) To ensure that this
-all works out smoothly, you must use the double-argument form of bless().
-The second argument is the class into which the referent will be blessed.
-By not assuming our own class as the default second argument and instead
-using the class passed into us, we make our constructor inheritable.
-
- sub new {
- my $class = shift;
- my $self = {};
- $self->{NAME} = undef;
- $self->{AGE} = undef;
- $self->{PEERS} = [];
- bless ($self, $class);
- return $self;
- }
-
-That's about all there is for constructors. These methods bring objects
-to life, returning neat little opaque bundles to the user to be used in
-subsequent method calls.
-
-=head2 Destructors
-
-Every story has a beginning and an end. The beginning of the object's
-story is its constructor, explicitly called when the object comes into
-existence. But the ending of its story is the I<destructor>, a method
-implicitly called when an object leaves this life. Any per-object
-clean-up code is placed in the destructor, which must (in Perl) be called
-DESTROY.
-
-If constructors can have arbitrary names, then why not destructors?
-Because while a constructor is explicitly called, a destructor is not.
-Destruction happens automatically via Perl's garbage collection (GC)
-system, which is a quick but somewhat lazy reference-based GC system.
-To know what to call, Perl insists that the destructor be named DESTROY.
-Perl's notion of the right time to call a destructor is not well-defined
-currently, which is why your destructors should not rely on when they are
-called.
-
-Why is DESTROY in all caps? Perl on occasion uses purely uppercase
-function names as a convention to indicate that the function will
-be automatically called by Perl in some way. Others that are called
-implicitly include BEGIN, END, AUTOLOAD, plus all methods used by
-tied objects, described in L<perltie>.
-
-In really good object-oriented programming languages, the user doesn't
-care when the destructor is called. It just happens when it's supposed
-to. In low-level languages without any GC at all, there's no way to
-depend on this happening at the right time, so the programmer must
-explicitly call the destructor to clean up memory and state, crossing
-their fingers that it's the right time to do so. Unlike C++, an
-object destructor is nearly never needed in Perl, and even when it is,
-explicit invocation is uncalled for. In the case of our Person class,
-we don't need a destructor because Perl takes care of simple matters
-like memory deallocation.
-
-The only situation where Perl's reference-based GC won't work is
-when there's a circularity in the data structure, such as:
-
- $this->{WHATEVER} = $this;
-
-In that case, you must delete the self-reference manually if you expect
-your program not to leak memory. While admittedly error-prone, this is
-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
-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.)
-
-=head2 Other Object Methods
-
-The methods we've talked about so far have either been constructors or
-else simple "data methods", interfaces to data stored in the object.
-These are a bit like an object's data members in the C++ world, except
-that strangers don't access them as data. Instead, they should only
-access the object's data indirectly via its methods. This is an
-important rule: in Perl, access to an object's data should I<only>
-be made through methods.
-
-Perl doesn't impose restrictions on who gets to use which methods.
-The public-versus-private distinction is by convention, not syntax.
-(Well, unless you use the Alias module described below in
-L<Data Members as Variables>.) Occasionally you'll see method names beginning or ending
-with an underscore or two. This marking is a convention indicating
-that the methods are private to that class alone and sometimes to its
-closest acquaintances, its immediate subclasses. But this distinction
-is not enforced by Perl itself. It's up to the programmer to behave.
-
-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.
-
- sub exclaim {
- my $self = shift;
- return sprintf "Hi, I'm %s, age %d, working with %s",
- $self->{NAME}, $self->{AGE}, join(", ", @{$self->{PEERS}});
- }
-
-Or maybe even one like this:
-
- sub happy_birthday {
- my $self = shift;
- return ++$self->{AGE};
- }
-
-Some might argue that one should go at these this way:
-
- sub exclaim {
- my $self = shift;
- return sprintf "Hi, I'm %s, age %d, working with %s",
- $self->name, $self->age, join(", ", $self->peers);
- }
-
- sub happy_birthday {
- my $self = shift;
- return $self->age( $self->age() + 1 );
- }
-
-But since these methods are all executing in the class itself, this
-may not be critical. There are tradeoffs to be made. Using direct
-hash access is faster (about an order of magnitude faster, in fact), and
-it's more convenient when you want to interpolate in strings. But using
-methods (the external interface) internally shields not just the users of
-your class but even you yourself from changes in your data representation.
-
-=head1 Class Data
-
-What about "class data", data items common to each object in a class?
-What would you want that for? Well, in your Person class, you might
-like to keep track of the total people alive. How do you implement that?
-
-You I<could> make it a global variable called $Person::Census. But about
-only reason you'd do that would be if you I<wanted> people to be able to
-get at your class data directly. They could just say $Person::Census
-and play around with it. Maybe this is ok in your design scheme.
-You might even conceivably want to make it an exported variable. To be
-exportable, a variable must be a (package) global. If this were a
-traditional module rather than an object-oriented one, you might do that.
-
-While this approach is expected in most traditional modules, it's
-generally considered rather poor form in most object modules. In an
-object module, you should set up a protective veil to separate interface
-from implementation. So provide a class method to access class data
-just as you provide object methods to access object data.
-
-So, you I<could> still keep $Census as a package global and rely upon
-others to honor the contract of the module and therefore not play around
-with its implementation. You could even be supertricky and make $Census a
-tied object as described in L<perltie>, thereby intercepting all accesses.
-
-But more often than not, you just want to make your class data a
-file-scoped lexical. To do so, simply put this at the top of the file:
-
- my $Census = 0;
-
-Even though the scope of a my() normally expires when the block in which
-it was declared is done (in this case the whole file being required or
-used), Perl's deep binding of lexical variables guarantees that the
-variable will not be deallocated, remaining accessible to functions
-declared within that scope. This doesn't work with global variables
-given temporary values via local(), though.
-
-Irrespective of whether you leave $Census a package global or make
-it instead a file-scoped lexical, you should make these
-changes to your Person::new() constructor:
-
- sub new {
- my $class = shift;
- my $self = {};
- $Census++;
- $self->{NAME} = undef;
- $self->{AGE} = undef;
- $self->{PEERS} = [];
- bless ($self, $class);
- return $self;
- }
-
- sub population {
- return $Census;
- }
-
-Now that we've done this, we certainly do need a destructor so that
-when Person is destroyed, the $Census goes down. Here's how
-this could be done:
-
- sub DESTROY { --$Census }
-
-Notice how there's no memory to deallocate in the destructor? That's
-something that Perl takes care of for you all by itself.
-
-Alternatively, you could use the Class::Data::Inheritable module from
-CPAN.
-
-
-=head2 Accessing Class Data
-
-It turns out that this is not really a good way to go about handling
-class data. A good scalable rule is that I<you must never reference class
-data directly from an object method>. Otherwise you aren't building a
-scalable, inheritable class. The object must be the rendezvous point
-for all operations, especially from an object method. The globals
-(class data) would in some sense be in the "wrong" package in your
-derived classes. In Perl, methods execute in the context of the class
-they were defined in, I<not> that of the object that triggered them.
-Therefore, namespace visibility of package globals in methods is unrelated
-to inheritance.
-
-Got that? Maybe not. Ok, let's say that some other class "borrowed"
-(well, inherited) the DESTROY method as it was defined above. When those
-objects are destroyed, the original $Census variable will be altered,
-not the one in the new class's package namespace. Perhaps this is what
-you want, but probably it isn't.
-
-Here's how to fix this. We'll store a reference to the data in the
-value accessed by the hash key "_CENSUS". Why the underscore? Well,
-mostly because an initial underscore already conveys strong feelings
-of magicalness to a C programmer. It's really just a mnemonic device
-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 perl version 5.004 we'll have to quote the field name.)
-
- sub new {
- my $class = shift;
- my $self = {};
- $self->{NAME} = undef;
- $self->{AGE} = undef;
- $self->{PEERS} = [];
- # "private" data
- $self->{"_CENSUS"} = \$Census;
- bless ($self, $class);
- ++ ${ $self->{"_CENSUS"} };
- return $self;
- }
-
- sub population {
- my $self = shift;
- if (ref $self) {
- return ${ $self->{"_CENSUS"} };
- } else {
- return $Census;
- }
- }
-
- sub DESTROY {
- my $self = shift;
- -- ${ $self->{"_CENSUS"} };
- }
-
-=head2 Debugging Methods
-
-It's common for a class to have a debugging mechanism. For example,
-you might want to see when objects are created or destroyed. To do that,
-add a debugging variable as a file-scoped lexical. For this, we'll pull
-in the standard Carp module to emit our warnings and fatal messages.
-That way messages will come out with the caller's filename and
-line number instead of our own; if we wanted them to be from our own
-perspective, we'd just use die() and warn() directly instead of croak()
-and carp() respectively.
-
- use Carp;
- my $Debugging = 0;
-
-Now add a new class method to access the variable.
-
- sub debug {
- my $class = shift;
- if (ref $class) { confess "Class method called as object method" }
- unless (@_ == 1) { confess "usage: CLASSNAME->debug(level)" }
- $Debugging = shift;
- }
-
-Now fix up DESTROY to murmur a bit as the moribund object expires:
-
- sub DESTROY {
- my $self = shift;
- if ($Debugging) { carp "Destroying $self " . $self->name }
- -- ${ $self->{"_CENSUS"} };
- }
-
-One could conceivably make a per-object debug state. That
-way you could call both of these:
-
- Person->debug(1); # entire class
- $him->debug(1); # just this object
-
-To do so, we need our debugging method to be a "bimodal" one, one that
-works on both classes I<and> objects. Therefore, adjust the debug()
-and DESTROY methods as follows:
-
- sub debug {
- my $self = shift;
- confess "usage: thing->debug(level)" unless @_ == 1;
- my $level = shift;
- if (ref($self)) {
- $self->{"_DEBUG"} = $level; # just myself
- } else {
- $Debugging = $level; # whole class
- }
- }
-
- sub DESTROY {
- my $self = shift;
- if ($Debugging || $self->{"_DEBUG"}) {
- carp "Destroying $self " . $self->name;
- }
- -- ${ $self->{"_CENSUS"} };
- }
-
-What happens if a derived class (which we'll call Employee) inherits
-methods from this Person base class? Then C<< Employee->debug() >>, when called
-as a class method, manipulates $Person::Debugging not $Employee::Debugging.
-
-=head2 Class Destructors
-
-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
-END. This works just like the END function in traditional modules,
-meaning that it gets called whenever your program exits unless it execs
-or dies of an uncaught signal. For example,
-
- sub END {
- if ($Debugging) {
- print "All persons are going away now.\n";
- }
- }
-
-When the program exits, all the class destructors (END functions) are
-be called in the opposite order that they were loaded in (LIFO order).
-
-=head2 Documenting the Interface
-
-And there you have it: we've just shown you the I<implementation> of this
-Person class. Its I<interface> would be its documentation. Usually this
-means putting it in pod ("plain old documentation") format right there
-in the same file. In our Person example, we would place the following
-docs anywhere in the Person.pm file. Even though it looks mostly like
-code, it's not. It's embedded documentation such as would be used by
-the pod2man, pod2html, or pod2text programs. The Perl compiler ignores
-pods entirely, just as the translators ignore code. Here's an example of
-some pods describing the informal interface:
-
- =head1 NAME
-
- Person - class to implement people
-
- =head1 SYNOPSIS
-
- use Person;
-
- #################
- # class methods #
- #################
- $ob = Person->new;
- $count = Person->population;
-
- #######################
- # object data methods #
- #######################
-
- ### get versions ###
- $who = $ob->name;
- $years = $ob->age;
- @pals = $ob->peers;
-
- ### set versions ###
- $ob->name("Jason");
- $ob->age(23);
- $ob->peers( "Norbert", "Rhys", "Phineas" );
-
- ########################
- # other object methods #
- ########################
-
- $phrase = $ob->exclaim;
- $ob->happy_birthday;
-
- =head1 DESCRIPTION
-
- The Person class implements dah dee dah dee dah....
-
-That's all there is to the matter of interface versus implementation.
-A programmer who opens up the module and plays around with all the private
-little shiny bits that were safely locked up behind the interface contract
-has voided the warranty, and you shouldn't worry about their fate.
-
-=head1 Aggregation
-
-Suppose you later want to change the class to implement better names.
-Perhaps you'd like to support both given names (called Christian names,
-irrespective of one's religion) and family names (called surnames), plus
-nicknames and titles. If users of your Person class have been properly
-accessing it through its documented interface, then you can easily change
-the underlying implementation. If they haven't, then they lose and
-it's their fault for breaking the contract and voiding their warranty.
-
-To do this, we'll make another class, this one called Fullname. What's
-the Fullname class look like? To answer that question, you have to
-first figure out how you want to use it. How about we use it this way:
-
- $him = Person->new();
- $him->fullname->title("St");
- $him->fullname->christian("Thomas");
- $him->fullname->surname("Aquinas");
- $him->fullname->nickname("Tommy");
- printf "His normal name is %s\n", $him->name;
- printf "But his real name is %s\n", $him->fullname->as_string;
-
-Ok. To do this, we'll change Person::new() so that it supports
-a full name field this way:
-
- sub new {
- my $class = shift;
- my $self = {};
- $self->{FULLNAME} = Fullname->new();
- $self->{AGE} = undef;
- $self->{PEERS} = [];
- $self->{"_CENSUS"} = \$Census;
- bless ($self, $class);
- ++ ${ $self->{"_CENSUS"} };
- return $self;
- }
-
- sub fullname {
- my $self = shift;
- return $self->{FULLNAME};
- }
-
-Then to support old code, define Person::name() this way:
-
- sub name {
- my $self = shift;
- return $self->{FULLNAME}->nickname(@_)
- || $self->{FULLNAME}->christian(@_);
- }
-
-Here's the Fullname class. We'll use the same technique
-of using a hash reference to hold data fields, and methods
-by the appropriate name to access them:
-
- package Fullname;
- use strict;
-
- sub new {
- my $class = shift;
- my $self = {
- TITLE => undef,
- CHRISTIAN => undef,
- SURNAME => undef,
- NICK => undef,
- };
- bless ($self, $class);
- return $self;
- }
-
- sub christian {
- my $self = shift;
- if (@_) { $self->{CHRISTIAN} = shift }
- return $self->{CHRISTIAN};
- }
-
- sub surname {
- my $self = shift;
- if (@_) { $self->{SURNAME} = shift }
- return $self->{SURNAME};
- }
-
- sub nickname {
- my $self = shift;
- if (@_) { $self->{NICK} = shift }
- return $self->{NICK};
- }
-
- sub title {
- my $self = shift;
- if (@_) { $self->{TITLE} = shift }
- return $self->{TITLE};
- }
-
- sub as_string {
- my $self = shift;
- my $name = join(" ", @$self{'CHRISTIAN', 'SURNAME'});
- if ($self->{TITLE}) {
- $name = $self->{TITLE} . " " . $name;
- }
- return $name;
- }
-
- 1;
-
-Finally, here's the test program:
-
- #!/usr/bin/perl -w
- use strict;
- use Person;
- sub END { show_census() }
-
- sub show_census () {
- printf "Current population: %d\n", Person->population;
- }
-
- Person->debug(1);
-
- show_census();
-
- my $him = Person->new();
-
- $him->fullname->christian("Thomas");
- $him->fullname->surname("Aquinas");
- $him->fullname->nickname("Tommy");
- $him->fullname->title("St");
- $him->age(1);
-
- printf "%s is really %s.\n", $him->name, $him->fullname->as_string;
- printf "%s's age: %d.\n", $him->name, $him->age;
- $him->happy_birthday;
- printf "%s's age: %d.\n", $him->name, $him->age;
-
- show_census();
-
-=head1 Inheritance
-
-Object-oriented programming systems all support some notion of
-inheritance. Inheritance means allowing one class to piggy-back on
-top of another one so you don't have to write the same code again and
-again. It's about software reuse, and therefore related to Laziness,
-the principal virtue of a programmer. (The import/export mechanisms in
-traditional modules are also a form of code reuse, but a simpler one than
-the true inheritance that you find in object modules.)
-
-Sometimes the syntax of inheritance is built into the core of the
-language, and sometimes it's not. Perl has no special syntax for
-specifying the class (or classes) to inherit from. Instead, it's all
-strictly in the semantics. Each package can have a variable called @ISA,
-which governs (method) inheritance. If you try to call a method on an
-object or class, and that method is not found in that object's package,
-Perl then looks to @ISA for other packages to go looking through in
-search of the missing method.
-
-Like the special per-package variables recognized by Exporter (such as
-@EXPORT, @EXPORT_OK, @EXPORT_FAIL, %EXPORT_TAGS, and $VERSION), the @ISA
-array I<must> be a package-scoped global and not a file-scoped lexical
-created via my(). Most classes have just one item in their @ISA array.
-In this case, we have what's called "single inheritance", or SI for short.
-
-Consider this class:
-
- package Employee;
- use Person;
- @ISA = ("Person");
- 1;
-
-Not a lot to it, eh? All it's doing so far is loading in another
-class and stating that this one will inherit methods from that
-other class if need be. We have given it none of its own methods.
-We rely upon an Employee to behave just like a Person.
-
-Setting up an empty class like this is called the "empty subclass test";
-that is, making a derived class that does nothing but inherit from a
-base class. If the original base class has been designed properly,
-then the new derived class can be used as a drop-in replacement for the
-old one. This means you should be able to write a program like this:
-
- use Employee;
- my $empl = Employee->new();
- $empl->name("Jason");
- $empl->age(23);
- printf "%s is age %d.\n", $empl->name, $empl->age;
-
-By proper design, we mean always using the two-argument form of bless(),
-avoiding direct access of global data, and not exporting anything. If you
-look back at the Person::new() function we defined above, we were careful
-to do that. There's a bit of package data used in the constructor,
-but the reference to this is stored on the object itself and all other
-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
-a method? Well, in principle, yes. A method is just a function that
-expects as its first argument a class name (package) or object
-(blessed reference). Person::new() is the function that both the
-C<< Person->new() >> method and the C<< Employee->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
-as the same, you'll very soon be left with nothing but broken programs.
-First, the actual underlying calling conventions are different: method
-calls get an extra argument. Second, function calls don't do inheritance,
-but methods do.
-
- Method Call Resulting Function Call
- ----------- ------------------------
- Person->new() Person::new("Person")
- Employee->new() Person::new("Employee")
-
-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
-data fields to access their salary, their employee ID, and their
-start date.
-
-If you're getting a little tired of creating all these nearly identical
-methods just to get at the object's data, do not despair. Later,
-we'll describe several different convenience mechanisms for shortening
-this up. Meanwhile, here's the straight-forward way:
-
- sub salary {
- my $self = shift;
- if (@_) { $self->{SALARY} = shift }
- return $self->{SALARY};
- }
-
- sub id_number {
- my $self = shift;
- if (@_) { $self->{ID} = shift }
- return $self->{ID};
- }
-
- sub start_date {
- my $self = shift;
- if (@_) { $self->{START_DATE} = shift }
- return $self->{START_DATE};
- }
-
-=head2 Overridden Methods
-
-What happens when both a derived class and its base class have the same
-method defined? Well, then you get the derived class's version of that
-method. For example, let's say that we want the peers() method called on
-an employee to act a bit differently. Instead of just returning the list
-of peer names, let's return slightly different strings. So doing this:
-
- $empl->peers("Peter", "Paul", "Mary");
- printf "His peers are: %s\n", join(", ", $empl->peers);
-
-will produce:
-
- His peers are: PEON=PETER, PEON=PAUL, PEON=MARY
-
-To do this, merely add this definition into the Employee.pm file:
-
- sub peers {
- my $self = shift;
- if (@_) { @{ $self->{PEERS} } = @_ }
- return map { "PEON=\U$_" } @{ $self->{PEERS} };
- }
-
-There, we've just demonstrated the high-falutin' concept known in certain
-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.)
-
-Every now and then you'll want to have a method call trigger both its
-derived class (also known as "subclass") version as well as its base class
-(also known as "superclass") version. In practice, constructors and
-destructors are likely to want to do this, and it probably also makes
-sense in the debug() method we showed previously.
-
-To do this, add this to Employee.pm:
-
- use Carp;
- my $Debugging = 0;
-
- sub debug {
- my $self = shift;
- confess "usage: thing->debug(level)" unless @_ == 1;
- my $level = shift;
- if (ref($self)) {
- $self->{"_DEBUG"} = $level;
- } else {
- $Debugging = $level; # whole class
- }
- Person::debug($self, $Debugging); # don't really do this
- }
-
-As you see, we turn around and call the Person package's debug() function.
-But this is far too fragile for good design. What if Person doesn't
-have a debug() function, but is inheriting I<its> debug() method
-from elsewhere? It would have been slightly better to say
-
- Person->debug($Debugging);
-
-But even that's got too much hard-coded. It's somewhat better to say
-
- $self->Person::debug($Debugging);
-
-Which is a funny way to say to start looking for a debug() method up
-in Person. This strategy is more often seen on overridden object methods
-than on overridden class methods.
-
-There is still something a bit off here. We've hard-coded our
-superclass's name. This in particular is bad if you change which classes
-you inherit from, or add others. Fortunately, the pseudoclass SUPER
-comes to the rescue here.
-
- $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
-in SUPER:: from anywhere else, because it doesn't exist outside
-an overridden method call. Note that C<SUPER> refers to the superclass of
-the current package, I<not> to the superclass of C<$self>.
-
-Things are getting a bit complicated here. Have we done anything
-we shouldn't? As before, one way to test whether we're designing
-a decent class is via the empty subclass test. Since we already have
-an Employee class that we're trying to check, we'd better get a new
-empty subclass that can derive from Employee. Here's one:
-
- package Boss;
- use Employee; # :-)
- @ISA = qw(Employee);
-
-And here's the test program:
-
- #!/usr/bin/perl -w
- use strict;
- use Boss;
- Boss->debug(1);
-
- my $boss = Boss->new();
-
- $boss->fullname->title("Don");
- $boss->fullname->surname("Pichon Alvarez");
- $boss->fullname->christian("Federico Jesus");
- $boss->fullname->nickname("Fred");
-
- $boss->age(47);
- $boss->peers("Frank", "Felipe", "Faust");
-
- printf "%s is age %d.\n", $boss->fullname->as_string, $boss->age;
- 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, somewhat like the way the 'x' command works in
-the debugger, you could use the Data::Dumper module from CPAN this way:
-
- use Data::Dumper;
- print "Here's the boss:\n";
- print Dumper($boss);
-
-Which shows us something like this:
-
- 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
-don't show up in the hash's keys. The Employee class has no new() method
-of its own, and the new() method in Person doesn't know about Employees.
-(Nor should it: proper OO design dictates that a subclass be allowed to
-know about its immediate superclass, but never vice-versa.) So let's
-fix up Employee::new() this way:
-
- sub new {
- my $class = shift;
- my $self = $class->SUPER::new();
- $self->{SALARY} = undef;
- $self->{ID} = undef;
- $self->{START_DATE} = undef;
- bless ($self, $class); # reconsecrate
- return $self;
- }
-
-Now if you dump out an Employee or Boss object, you'll find
-that new fields show up there now.
-
-=head2 Multiple Inheritance
-
-Ok, at the risk of confusing beginners and annoying OO gurus, it's
-time to confess that Perl's object system includes that controversial
-notion known as multiple inheritance, or MI for short. All this means
-is that rather than having just one parent class who in turn might
-itself have a parent class, etc., that you can directly inherit from
-two or more parents. It's true that some uses of MI can get you into
-trouble, although hopefully not quite so much trouble with Perl as with
-dubiously-OO languages like C++.
-
-The way it works is actually pretty simple: just put more than one package
-name in your @ISA array. When it comes time for Perl to go finding
-methods for your object, it looks at each of these packages in order.
-Well, kinda. It's actually a fully recursive, depth-first order by
-default (see L<mro> for alternate method resolution orders).
-Consider a bunch of @ISA arrays like this:
-
- @First::ISA = qw( Alpha );
- @Second::ISA = qw( Beta );
- @Third::ISA = qw( First Second );
-
-If you have an object of class Third:
-
- my $ob = Third->new();
- $ob->spin();
-
-How do we find a spin() method (or a new() method for that matter)?
-Because the search is depth-first, classes will be looked up
-in the following order: Third, First, Alpha, Second, and Beta.
-
-In practice, few class modules have been seen that actually
-make use of MI. One nearly always chooses simple containership of
-one class within another over MI. That's why our Person
-object I<contained> a Fullname object. That doesn't mean
-it I<was> one.
-
-However, there is one particular area where MI in Perl is rampant:
-borrowing another class's class methods. This is rather common,
-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 entirely clear why inheritance was done
-here rather than traditional module importation.)
-
-For example, here is the POSIX module's @ISA:
-
- package POSIX;
- @ISA = qw(Exporter DynaLoader);
-
-The POSIX module isn't really an object module, but then,
-neither are Exporter or DynaLoader. They're just lending their
-classes' behaviours to POSIX.
-
-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, 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
-two parent classes? The SUPER notation would only find the first one.
-Also, what about if the Alpha and Beta classes both had a common ancestor,
-like Nought? If you kept climbing up the inheritance tree calling
-overridden methods, you'd end up calling Nought::new() twice,
-which might well be a bad idea.
-
-=head2 UNIVERSAL: The Root of All Objects
-
-Wouldn't it be convenient if all objects were rooted at some ultimate
-base class? That way you could give every object common methods without
-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 version 5.003, there were no predefined methods there, but you could put
-whatever you felt like into it.
-
-However, as of version 5.004 (or some subversive releases, like 5.003_08),
-UNIVERSAL has some methods in it already. These are builtin 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
-class "is" another one without having to traverse the hierarchy yourself:
-
- $has_io = $fd->isa("IO::Handle");
- $itza_handle = IO::Socket->isa("IO::Handle");
-
-The can() method, called against that object or class, reports back
-whether its string argument is a callable method name in that class.
-In fact, it gives you back a function reference to that method:
-
- $his_print_method = $obj->can('as_string');
-
-Finally, the VERSION method checks whether the class (or the object's
-class) has a package global called $VERSION that's high enough, as in:
-
- Some_Module->VERSION(3.0);
- $his_vers = $ob->VERSION();
-
-However, we don't usually call VERSION ourselves. (Remember that an all
-uppercase function name is a Perl convention that indicates that the
-function will be automatically used by Perl in some way.) In this case,
-it happens when you say
-
- use Some_Module 3.0;
-
-If you wanted to add version checking to your Person class explained
-above, just add this to Person.pm:
-
- our $VERSION = '1.1';
-
-and then in Employee.pm you can say
-
- use Person 1.1;
-
-And it would make sure that you have at least that version number or
-higher available. This is not the same as loading in that exact version
-number. No mechanism currently exists for concurrent installation of
-multiple versions of a module. Lamentably.
-
-=head2 Deeper UNIVERSAL details
-
-It is also valid (though perhaps unwise in most cases) to put other
-packages' names in @UNIVERSAL::ISA. These packages will also be
-implicitly inherited by all classes, just as UNIVERSAL itself is.
-However, neither UNIVERSAL nor any of its parents from the @ISA tree
-are explicit base classes of all objects. To clarify, given the
-following:
-
- @UNIVERSAL::ISA = ('REALLYUNIVERSAL');
-
- package REALLYUNIVERSAL;
- sub special_method { return "123" }
-
- package Foo;
- sub normal_method { return "321" }
-
-Calling Foo->special_method() will return "123", but calling
-Foo->isa('REALLYUNIVERSAL') or Foo->isa('UNIVERSAL') will return
-false.
-
-If your class is using an alternate mro like C3 (see
-L<mro>), method resolution within UNIVERSAL / @UNIVERSAL::ISA will
-still occur in the default depth-first left-to-right manner,
-after the class's C3 mro is exhausted.
-
-All of the above is made more intuitive by realizing what really
-happens during method lookup, which is roughly like this
-ugly pseudo-code:
-
- get_mro(class) {
- # recurses down the @ISA's starting at class,
- # builds a single linear array of all
- # classes to search in the appropriate order.
- # The method resolution order (mro) to use
- # for the ordering is whichever mro "class"
- # has set on it (either default (depth first
- # l-to-r) or C3 ordering).
- # The first entry in the list is the class
- # itself.
- }
-
- find_method(class, methname) {
- foreach $class (get_mro(class)) {
- if($class->has_method(methname)) {
- return ref_to($class->$methname);
- }
- }
- foreach $class (get_mro(UNIVERSAL)) {
- if($class->has_method(methname)) {
- return ref_to($class->$methname);
- }
- }
- return undef;
- }
-
-However the code that implements UNIVERSAL::isa does not
-search in UNIVERSAL itself, only in the package's actual
-@ISA.
-
-=head1 Alternate Object Representations
-
-Nothing requires objects to be implemented as hash references. An object
-can be any sort of reference so long as its referent has been suitably
-blessed. That means scalar, array, and code references are also fair
-game.
-
-A scalar would work if the object has only one datum to hold. An array
-would work for most cases, but makes inheritance a bit dodgy because
-you have to invent new indices for the derived classes.
-
-=head2 Arrays as Objects
-
-If the user of your class honors the contract and sticks to the advertised
-interface, then you can change its underlying interface if you feel
-like it. Here's another implementation that conforms to the same
-interface specification. This time we'll use an array reference
-instead of a hash reference to represent the object.
-
- package Person;
- use strict;
-
- my($NAME, $AGE, $PEERS) = ( 0 .. 2 );
-
- ############################################
- ## the object constructor (array version) ##
- ############################################
- sub new {
- my $self = [];
- $self->[$NAME] = undef; # this is unnecessary
- $self->[$AGE] = undef; # as is this
- $self->[$PEERS] = []; # but this isn't, really
- bless($self);
- return $self;
- }
-
- sub name {
- my $self = shift;
- if (@_) { $self->[$NAME] = shift }
- return $self->[$NAME];
- }
-
- sub age {
- my $self = shift;
- if (@_) { $self->[$AGE] = shift }
- return $self->[$AGE];
- }
-
- sub peers {
- my $self = shift;
- if (@_) { @{ $self->[$PEERS] } = @_ }
- return @{ $self->[$PEERS] };
- }
-
- 1; # so the require or use succeeds
-
-You might guess that the array access would be a lot faster than the
-hash access, but they're actually comparable. The array is a I<little>
-bit faster, but not more than ten or fifteen percent, even when you
-replace the variables above like $AGE with literal numbers, like 1.
-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 allocate memory for the keys as well as for the values.
-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.
-
-Still, the tiny edge in speed (and somewhat larger one in memory)
-is enough to make some programmers choose an array representation
-for simple classes. There's still a little problem with
-scalability, though, because later in life when you feel
-like creating subclasses, you'll find that hashes just work
-out better.
-
-=head2 Closures as Objects
-
-Using a code reference to represent an object offers some fascinating
-possibilities. We can create a new anonymous function (closure) who
-alone in all the world can see the object's data. This is because we
-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 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? :-)
-
-Use would be similar to before:
-
- use Person;
- $him = Person->new();
- $him->name("Jason");
- $him->age(23);
- $him->peers( [ "Norbert", "Rhys", "Phineas" ] );
- printf "%s is %d years old.\n", $him->name, $him->age;
- print "His peers are: ", join(", ", @{$him->peers}), "\n";
-
-but the implementation would be radically, perhaps even sublimely
-different:
-
- package Person;
-
- sub new {
- my $class = shift;
- my $self = {
- NAME => undef,
- AGE => undef,
- PEERS => [],
- };
- my $closure = sub {
- my $field = shift;
- if (@_) { $self->{$field} = shift }
- return $self->{$field};
- };
- bless($closure, $class);
- return $closure;
- }
-
- sub name { &{ $_[0] }("NAME", @_[ 1 .. $#_ ] ) }
- sub age { &{ $_[0] }("AGE", @_[ 1 .. $#_ ] ) }
- sub peers { &{ $_[0] }("PEERS", @_[ 1 .. $#_ ] ) }
-
- 1;
-
-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
-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 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 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
-that's just what we do when we say C<&{$_[0]}>. This is just a regular
-function call, not a method call. The initial argument is the string
-"NAME", and any remaining arguments are whatever had been passed to the
-method itself.
-
-Once we're executing inside the closure that had been created in new(),
-the $self hash reference suddenly becomes visible. The closure grabs
-its first argument ("NAME" in this case because that's what the name()
-method passed it), and uses that string to subscript into the private
-hash hidden in its unique version of $self.
-
-Nothing under the sun will allow anyone outside the executing method to
-be able to get at this hidden data. Well, nearly nothing. You I<could>
-single step through the program using the debugger and find out the
-pieces while you're in the method, but everyone else is out of luck.
-
-There, if that doesn't excite the Scheme folks, then I just don't know
-what will. Translation of this technique into C++, Java, or any other
-braindead-static language is left as a futile exercise for aficionados
-of those camps.
-
-You could even add a bit of nosiness via the caller() function and
-make the closure refuse to operate unless called via its own package.
-This would no doubt satisfy certain fastidious concerns of programming
-police and related puritans.
-
-If you were wondering when Hubris, the third principle virtue of a
-programmer, would come into play, here you have it. (More seriously,
-Hubris is just the pride in craftsmanship that comes from having written
-a sound bit of well-designed code.)
-
-=head1 AUTOLOAD: Proxy Methods
-
-Autoloading is a way to intercept calls to undefined methods. An autoload
-routine may choose to create a new function on the fly, either loaded
-from disk or perhaps just eval()ed right there. This define-on-the-fly
-strategy is why it's called autoloading.
-
-But that's only one possible approach. Another one is to just
-have the autoloaded method itself directly provide the
-requested service. When used in this way, you may think
-of autoloaded methods as "proxy" methods.
-
-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.
-The fully-qualified name of the function is stored in that package's
-global variable $AUTOLOAD. Once called, the function can do anything
-it would like, including defining a new function by the right name, and
-then doing a really fancy kind of C<goto> right to it, erasing itself
-from the call stack.
-
-What does this have to do with objects? After all, we keep talking about
-functions, not methods. Well, since a method is just a function with
-an extra argument and some fancier semantics about where it's found,
-we can use autoloading for methods, too. Perl doesn't start looking
-for an AUTOLOAD method until it has exhausted the recursive hunt up
-through @ISA, though. Some programmers have even been known to define
-a UNIVERSAL::AUTOLOAD method to trap unresolved method calls to any
-kind of object.
-
-=head2 Autoloaded Data Methods
-
-You probably began to get a little suspicious about the duplicated
-code way back earlier when we first showed you the Person class, and
-then later the Employee class. Each method used to access the
-hash fields looked virtually identical. This should have tickled
-that great programming virtue, Impatience, but for the time,
-we let Laziness win out, and so did nothing. Proxy methods can cure
-this.
-
-Instead of writing a new function every time we want a new data field,
-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-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".
-
-Here's what the module initialization code and class
-constructor will look like when taking this approach:
-
- package Person;
- use Carp;
- our $AUTOLOAD; # it's a package global
-
- my %fields = (
- name => undef,
- age => undef,
- peers => undef,
- );
-
- sub new {
- my $class = shift;
- my $self = {
- _permitted => \%fields,
- %fields,
- };
- bless $self, $class;
- return $self;
- }
-
-If we wanted our record to have default values, we could fill those in
-where current we have C<undef> in the %fields hash.
-
-Notice how we saved a reference to our class data on the object itself?
-Remember that it's important to access class data through the object
-itself instead of having any method reference %fields directly, or else
-you won't have a decent inheritance.
-
-The real magic, though, is going to reside in our proxy method, which
-will handle all calls to undefined methods for objects of class Person
-(or subclasses of Person). It has to be called AUTOLOAD. Again, it's
-all caps because it's called for us implicitly by Perl itself, not by
-a user directly.
-
- sub AUTOLOAD {
- my $self = shift;
- my $type = ref($self)
- or croak "$self is not an object";
-
- my $name = $AUTOLOAD;
- $name =~ s/.*://; # strip fully-qualified portion
-
- unless (exists $self->{_permitted}->{$name} ) {
- croak "Can't access `$name' field in class $type";
- }
-
- if (@_) {
- return $self->{$name} = shift;
- } else {
- return $self->{$name};
- }
- }
-
-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
-class similarly? Yes, so long as we're careful enough.
-
-Here's how to be careful:
-
- package Employee;
- use Person;
- use strict;
- our @ISA = qw(Person);
-
- my %fields = (
- id => undef,
- salary => undef,
- );
-
- sub new {
- my $class = shift;
- my $self = $class->SUPER::new();
- my($element);
- foreach $element (keys %fields) {
- $self->{_permitted}->{$element} = $fields{$element};
- }
- @{$self}{keys %fields} = values %fields;
- return $self;
- }
-
-Once we've done this, we don't even need to have an
-AUTOLOAD function in the Employee package, because
-we'll grab Person's version of that via inheritance,
-and it will all work out just fine.
-
-=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
-functions, it still leaves a bit to be desired. For one thing, it means
-you have to handle bogus calls that you don't mean to trap via your proxy.
-It also means you have to be quite careful when dealing with inheritance,
-as detailed above.
-
-Perl programmers have responded to this by creating several different
-class construction classes. These metaclasses are classes
-that create other classes. A couple worth looking at are
-Class::Struct and Alias. These and other related metaclasses can be
-found in the modules directory on CPAN.
-
-=head2 Class::Struct
-
-One of the older ones is Class::Struct. 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 specific type. The function
-that does this is called, not surprisingly enough, struct(). Because
-structures or records are not base types in Perl, each time you want to
-create a class to provide a record-like data object, you yourself have
-to define a new() method, plus separate data-access methods for each of
-that record's fields. You'll quickly become bored with this process.
-The Class::Struct::struct() function alleviates this tedium.
-
-Here's a simple example of using it:
-
- use Class::Struct qw(struct);
- use Jobbie; # user-defined; see below
-
- struct 'Fred' => {
- one => '$',
- many => '@',
- profession => 'Jobbie', # does not call Jobbie->new()
- };
-
- $ob = Fred->new(profession => Jobbie->new());
- $ob->one("hmmmm");
-
- $ob->many(0, "here");
- $ob->many(1, "you");
- $ob->many(2, "go");
- print "Just set: ", $ob->many(2), "\n";
-
- $ob->profession->salary(10_000);
-
-You can declare types in the struct to be basic Perl types, or
-user-defined types (classes). User types will be initialized by calling
-that class's new() method.
-
-Take care that the C<Jobbie> object is not created automatically by the
-C<Fred> class's new() method, so you should specify a C<Jobbie> object
-when you create an instance of C<Fred>.
-
-Here's a real-world example of using struct generation. Let's say you
-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.
-
- use Socket;
- use Net::hostent;
- $h = gethostbyname("perl.com"); # object return
- printf "perl.com's real name is %s, address %s\n",
- $h->name, inet_ntoa($h->addr);
-
-Here's how to do this using the Class::Struct module.
-The crux is going to be this call:
-
- struct 'Net::hostent' => [ # note bracket
- name => '$',
- aliases => '@',
- addrtype => '$',
- 'length' => '$',
- addr_list => '@',
- ];
-
-Which creates object methods of those names and types.
-It even creates a new() method for us.
-
-We could also have implemented our object this way:
-
- struct 'Net::hostent' => { # note brace
- name => '$',
- aliases => '@',
- addrtype => '$',
- 'length' => '$',
- addr_list => '@',
- };
-
-and then Class::Struct would have used an anonymous hash as the object
-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,
-this time we'll opt for better speed and size over better flexibility.
-
-Here's the whole implementation:
-
- package Net::hostent;
- use strict;
-
- BEGIN {
- use Exporter ();
- our @EXPORT = qw(gethostbyname gethostbyaddr gethost);
- our @EXPORT_OK = qw(
- $h_name @h_aliases
- $h_addrtype $h_length
- @h_addr_list $h_addr
- );
- our %EXPORT_TAGS = ( FIELDS => [ @EXPORT_OK, @EXPORT ] );
- }
- our @EXPORT_OK;
-
- # Class::Struct forbids use of @ISA
- sub import { goto &Exporter::import }
-
- use Class::Struct qw(struct);
- struct 'Net::hostent' => [
- name => '$',
- aliases => '@',
- addrtype => '$',
- 'length' => '$',
- addr_list => '@',
- ];
-
- sub addr { shift->addr_list->[0] }
-
- sub populate (@) {
- return unless @_;
- my $hob = new(); # Class::Struct made this!
- $h_name = $hob->[0] = $_[0];
- @h_aliases = @{ $hob->[1] } = split ' ', $_[1];
- $h_addrtype = $hob->[2] = $_[2];
- $h_length = $hob->[3] = $_[3];
- $h_addr = $_[4];
- @h_addr_list = @{ $hob->[4] } = @_[ (4 .. $#_) ];
- return $hob;
- }
-
- sub gethostbyname ($) { populate(CORE::gethostbyname(shift)) }
-
- sub gethostbyaddr ($;$) {
- my ($addr, $addrtype);
- $addr = shift;
- require Socket unless @_;
- $addrtype = @_ ? shift : Socket::AF_INET();
- populate(CORE::gethostbyaddr($addr, $addrtype))
- }
-
- sub gethost($) {
- if ($_[0] =~ /^\d+(?:\.\d+(?:\.\d+(?:\.\d+)?)?)?$/) {
- require Socket;
- &gethostbyaddr(Socket::inet_aton(shift));
- } else {
- &gethostbyname;
- }
- }
-
- 1;
-
-We've snuck in quite a fair bit of other concepts besides just dynamic
-class creation, like overriding core functions, import/export bits,
-function prototyping, short-cut function call via C<&whatever>, and
-function replacement with C<goto &whatever>. These all mostly make
-sense from the perspective of a traditional module, but as you can see,
-we can also use them in an object module.
-
-You can look at other object-based, struct-like overrides of core
-functions in the 5.004 release of Perl in File::stat, Net::hostent,
-Net::netent, Net::protoent, Net::servent, Time::gmtime, Time::localtime,
-User::grent, and User::pwent. These modules have a final component
-that's all lowercase, by convention reserved for compiler pragmas,
-because they affect the compilation and change a builtin function.
-They also have the type names that a C programmer would most expect.
-
-=head2 Data Members as Variables
-
-If you're used to C++ objects, then you're accustomed to being able to
-get at an object's data members as simple variables from within a method.
-The Alias module provides for this, as well as a good bit more, such
-as the possibility of private methods that the object can call but folks
-outside the class cannot.
-
-Here's an example of creating a Person using the Alias module.
-When you update these magical instance variables, you automatically
-update value fields in the hash. Convenient, eh?
-
- package Person;
-
- # this is the same as before...
- sub new {
- my $class = shift;
- my $self = {
- NAME => undef,
- AGE => undef,
- PEERS => [],
- };
- bless($self, $class);
- return $self;
- }
-
- use Alias qw(attr);
- our ($NAME, $AGE, $PEERS);
-
- sub name {
- my $self = attr shift;
- if (@_) { $NAME = shift; }
- return $NAME;
- }
-
- sub age {
- my $self = attr shift;
- if (@_) { $AGE = shift; }
- return $AGE;
- }
-
- sub peers {
- my $self = attr shift;
- if (@_) { @PEERS = @_; }
- return @PEERS;
- }
-
- sub exclaim {
- my $self = attr shift;
- return sprintf "Hi, I'm %s, age %d, working with %s",
- $NAME, $AGE, join(", ", @PEERS);
- }
-
- sub happy_birthday {
- my $self = attr shift;
- return ++$AGE;
- }
-
-The need for the C<our> declaration is because what Alias does
-is play with package globals with the same name as the fields. To use
-globals while C<use strict> is in effect, you have to predeclare them.
-These package variables are localized to the block enclosing the attr()
-call just as if you'd used a local() on them. However, that means that
-they're still considered global variables with temporary values, just
-as with any other local().
-
-It would be nice to combine Alias with
-something like Class::Struct or Class::MethodMaker.
-
-=head1 NOTES
-
-=head2 Object Terminology
-
-In the various OO literature, it seems that a lot of different words
-are used to describe only a few different concepts. If you're not
-already an object programmer, then you don't need to worry about all
-these fancy words. But if you are, then you might like to know how to
-get at the same concepts in Perl.
-
-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
-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<superclass> all describe
-the same notion, whereas I<derived class>, I<specific class>, and
-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>.
-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
-object (one expecting a reference), or vice versa.
-
-From the C++ perspective, all methods in Perl are virtual.
-This, by the way, is why they are never checked for function
-prototypes in the argument list as regular builtin and user-defined
-functions can be.
-
-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>
-behaviour, not I<defining> mechanism) idea. C++ supports the latter
-notion, but not the former.
-
-=head1 SEE ALSO
-
-The following manpages will doubtless provide more
-background for this one:
-L<perlmod>,
-L<perlref>,
-L<perlobj>,
-L<perlbot>,
-L<perltie>,
-and
-L<overload>.
-
-L<perlboot> is a kinder, gentler introduction to object-oriented
-programming.
-
-L<perltooc> provides more detail on class data.
-
-Some modules which might prove interesting are Class::Accessor,
-Class::Class, Class::Contract, Class::Data::Inheritable,
-Class::MethodMaker and Tie::SecureHash
-
-
-=head1 AUTHOR AND COPYRIGHT
-
-Copyright (c) 1997, 1998 Tom Christiansen
-All rights reserved.
-
-This documentation is free; you can redistribute it and/or modify it
-under the same terms as Perl itself.
-
-Irrespective of its distribution, all code examples in this file
-are hereby placed into the public domain. You are permitted and
-encouraged to use this code in your own programs for fun
-or for profit as you see fit. A simple comment in the code giving
-credit would be courteous but is not required.
-
-=head1 COPYRIGHT
-
-=head2 Acknowledgments
-
-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.