=head2 Object Representation
By far the most common mechanism used in Perl to represent a Pascal
-record, a C struct, or a C++ class an anonymous hash. That's because a
+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.
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 an even one instead, you can't expect the compiler to catch this.
+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,
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 upper-case
+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
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
+(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
}
But since these methods are all executing in the class itself, this
-may not be critical. There are trade-offs to be made. Using direct
+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
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 destructed, the original $Census variable will be altered,
+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.
-- ${ $self->{"_CENSUS"} };
}
-What happens if a derived class (which we'll all C<Employee>) inherits
-methods from this person one? Then C<Employee->debug()> when called
-as a class method manipulates $Person::Debugging not $Employee::Debugging.
+What happens if a derived class (which we'll call Employee) inherits
+methods from this Person base class? Then C<Employee-E<gt>debug()>, when called
+as a class method, manipulates $Person::Debugging not $Employee::Debugging.
=head2 Class Destructors
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
+ use Employee;
my $empl = Employee->new();
$empl->name("Jason");
$empl->age(23);
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 know as "subclass") version as well as its base class
+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.
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 built-in to your Perl
+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:
$his_vers = $ob->VERSION();
However, we don't usually call VERSION ourselves. (Remember that an all
-upper-case function name is a Perl convention that indicates that the
+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 versioning to your Person class explained
+If you wanted to add version checking to your Person class explained
above, just add this to Person.pm:
use vars qw($VERSION);
sub new {
my $self = [];
$self->[$NAME] = undef; # this is unnecessary
- $self->[$AGE] = undef; # as it this
+ $self->[$AGE] = undef; # as is this
$self->[$PEERS] = []; # but this isn't, really
bless($self);
return $self;
1; # so the require or use succeeds
-You might guess that the array access will be a lot faster than the
-hash access, but they're actually comparable. The array is a little
+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 allocation memory for the keys as well as the values.
+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
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
+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
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
+object so you wouldn't have to access that class data
directly from an object method.
=head2 Inherited Autoloaded Data Methods
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::Template and Alias. These and other related metaclasses can be
+Class::Struct and Alias. These and other related metaclasses can be
found in the modules directory on CPAN.
-=head2 Class::Template
+=head2 Class::Struct
-One of the older ones is Class::Template. In fact, its syntax and
+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().
+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::Template qw(struct);
+ use Class::Struct qw(struct);
use Jobbie; # user-defined; see below
struct 'Fred' => {
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::Template module.
+Here's how to do this using the Class::Struct module.
The crux is going to be this call:
struct 'Net::hostent' => [ # note bracket
addr_list => '@',
};
-and then Class::Template would have used an anonymous hash as the object
+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,
BEGIN {
use Exporter ();
- use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
- @ISA = qw(Exporter);
+ use vars qw(@EXPORT @EXPORT_OK %EXPORT_TAGS);
@EXPORT = qw(gethostbyname gethostbyaddr gethost);
@EXPORT_OK = qw(
$h_name @h_aliases
}
use vars @EXPORT_OK;
- use Class::Template qw(struct);
+ # Class::Struct forbids use of @ISA
+ sub import { goto &Exporter::import }
+
+ use Class::Struct qw(struct);
struct 'Net::hostent' => [
name => '$',
aliases => '@',
sub populate (@) {
return unless @_;
- my $hob = new(); # Class::Template made this!
+ my $hob = new(); # Class::Struct made this!
$h_name = $hob->[0] = $_[0];
@h_aliases = @{ $hob->[1] } = split ' ', $_[1];
$h_addrtype = $hob->[2] = $_[2];
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, and short-cut function call via C<&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.
+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 lower-case, by convention reserved for compiler pragmas,
-because they affect the compilation and change a built-in function.
+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
The need for the C<use vars> 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 pre-declare them.
+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::Template or Class::MethodMaker.
+something like Class::Struct or Class::MethodMaker.
=head2 NOTES
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.
+Z<>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 built-in and user-defined
+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
=head1 SEE ALSO
-The following man pages will doubtless provide more
+The following manpages will doubtless provide more
background for this one:
L<perlmod>,
L<perlref>,
Copyright 1996 Tom Christiansen. All Rights Reserved.
This work derives in part from the second edition of I<Programming Perl>.
-Although destined for release as a man page with the standard Perl
+Although destined for release as a manpage with the standard Perl
distribution, it is not public domain (nor is any of Perl and its docset:
publishers beware). It's expected to someday make its way into a revision
of the Camel Book. While it is copyright by me with all rights reserved,