By not assuming our own class as the default second argument and instead
using the class passed into us, we make our constructor inheritable.
-While we're at it, let's make our constructor a bit more flexible.
-Rather than being uniquely a class method, we'll set it up so that
-it can be called as either a class method I<or> an object
-method. That way you can say:
-
- $me = Person->new();
- $him = $me->new();
-
-To do this, all we have to do is check whether what was passed in
-was a reference or not. If so, we were invoked as an object method,
-and we need to extract the package (class) using the ref() function.
-If not, we just use the string passed in as the package name
-for blessing our referent.
-
sub new {
- my $proto = shift;
- my $class = ref($proto) || $proto;
+ my $class = shift;
my $self = {};
$self->{NAME} = undef;
$self->{AGE} = undef;
changes to your Person::new() constructor:
sub new {
- my $proto = shift;
- my $class = ref($proto) || $proto;
+ my $class = shift;
my $self = {};
$Census++;
$self->{NAME} = undef;
to perl version 5.004 we'll have to quote the field name.)
sub new {
- my $proto = shift;
- my $class = ref($proto) || $proto;
+ my $class = shift;
my $self = {};
$self->{NAME} = undef;
$self->{AGE} = undef;
a full name field this way:
sub new {
- my $proto = shift;
- my $class = ref($proto) || $proto;
+ my $class = shift;
my $self = {};
$self->{FULLNAME} = Fullname->new();
$self->{AGE} = undef;
use strict;
sub new {
- my $proto = shift;
- my $class = ref($proto) || $proto;
+ my $class = shift;
my $self = {
TITLE => undef,
CHRISTIAN => undef,
fix up Employee::new() this way:
sub new {
- my $proto = shift;
- my $class = ref($proto) || $proto;
+ my $class = shift;
my $self = $class->SUPER::new();
$self->{SALARY} = undef;
$self->{ID} = undef;
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.
+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 );
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
package Person;
sub new {
- my $that = shift;
- my $class = ref($that) || $that;
+ my $class = shift;
my $self = {
NAME => undef,
AGE => undef,
);
sub new {
- my $that = shift;
- my $class = ref($that) || $that;
+ my $class = shift;
my $self = {
_permitted => \%fields,
%fields,
);
sub new {
- my $that = shift;
- my $class = ref($that) || $that;
- my $self = bless $that->SUPER::new(), $class;
+ my $class = shift;
+ my $self = $class->SUPER::new();
my($element);
foreach $element (keys %fields) {
$self->{_permitted}->{$element} = $fields{$element};
# this is the same as before...
sub new {
- my $that = shift;
- my $class = ref($that) || $that;
+ my $class = shift;
my $self = {
NAME => undef,
AGE => undef,