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 calss to locate the
+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:
Inside C<Horse::name>, the C<@_> array contains:
- (C<$horse>, "some", "unnecessary", "args")
+ ($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">.
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.
+not only blesses C<\$name>, it also returns that reference.
This C<Horse::named> method is called a "constructor".
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:
+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";
}
-
-And of course C<named> still builds a scalar sheep, so let's fix that
-as well:
-
- ## in Animal
sub named {
my $class = shift;
my $name = shift;
- my $self = { Name => $name, Color => $class->default_color };
+ 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 initial color.
+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" }
-And then to keep from having to define one for each additional class,
-we'll define a "backstop" method that serves as the "default default",
-directly in C<Animal>:
+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" }
-Now, because C<name> and C<named> were the only methods that
+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 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, subclasses that add instance data, per-class
-data, overloading, "isa" and "can" tests, C<UNIVERSAL> class, and so
-on. That's for the rest of the Perl documentation to cover.
-Hopefully, this gets you started, though.
+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
=head1 COPYRIGHT
Copyright (c) 1999, 2000 by Randal L. Schwartz and Stonehenge
-Consulting Services, Inc. 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.
+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