12.5. Class InheritanceAs with the rest of Perl's object system, inheritance of one class by another requires no special syntax to be added to the language. When you invoke a method for which Perl finds no subroutine in the invocant's package, that package's @ISA array[5] is examined. This is how Perl implements inheritance: each element of a given package's @ISA array holds the name of another package, which is searched when methods are missing. For example, the following makes the Horse class a subclass of the Critter class. (We declare @ISA with our because it has to be a package variable, not a lexical declared with my.) You should now be able to use a Horse class or object everywhere that a Critter was previously used. If your new class passes this empty subclass test, you know that Critter is a proper base class, fit for inheritance.package Horse; our @ISA = "Critter";
Suppose you have a Horse object in $steed and invoke a move method on it: Because $steed is a Horse, Perl's first choice for that method is the Horse::move subroutine. If there isn't one, instead of raising a run-time exception, Perl consults the first element of @Horse::ISA, which directs it to look in the Critter package for Critter::move. If this subroutine isn't found either, and Critter has its own @Critter::ISA array, then that too will be consulted for the name of an ancestral package that might supply a move method, and so on back up the inheritance hierarchy until we come to a package without an @ISA.$steed->move(10); The situation we just described is single inheritance, where each class has only one parent. Such inheritance is like a linked list of related packages. Perl also supports multiple inheritance; just add more packages to the class's @ISA. This kind of inheritance works more like a tree data structure, because every package can have more than one immediate parent. Some people find this to be sexier. When you invoke a method methname on an invocant of type classname, Perl tries six different ways to find a subroutine to use:
Perl stops after the first successful attempt and invokes that subroutine. If no subroutine is found, an exception is raised, one that you'll see frequently: If you've built a debugging version of Perl using the -DDEBUGGING option to your C compiler, by using Perl's -Do switch, you can watch it go through each of these steps when it resolves method invocation.Can't locate object method "methname" via package "classname" We will discuss the inheritance mechanism in more detail as we go along. 12.5.1. Inheritance Through @ISAIf @ISA contains more than one package name, the packages are all searched in left-to-right order. The search is depth-first, so if you have a Mule class set up for inheritance this way: Perl looks for any methods missing from Mule first in Horse (and any of its ancestors, like Critter) before going on to search through Donkey and its ancestors.package Mule; our @ISA = ("Horse", "Donkey"); If a missing method is found in a base class, Perl internally caches that location in the current class for efficiency, so the next time it has to find the method, it doesn't have to look as far. Changing @ISA or defining new methods invalidates the cache and causes Perl to perform the lookup again. When Perl searches for a method, it makes sure that you haven't created a circular inheritance hierarchy. This could happen if two classes inherit from one another, even indirectly through other classes. Trying to be your own great-grandfather is too paradoxical even for Perl, so the attempt raises an exception. However, Perl does not consider it an error to inherit from more than one class sharing a common ancestry, which is rather like cousins marrying. Your inheritance hierarchy just stops looking like a tree and starts to look like a directed acyclic graph. This doesn't bother Perl--so long as the graph really is acyclic. When you set @ISA, the assignment normally happens at run time, so unless you take precautions, code in BEGIN, CHECK, or INIT blocks won't be able to use the inheritance hierarchy. One precaution (or convenience) is the use base pragma, which lets you require classes and add them to @ISA at compile time. Here's how you might use it: This is a shorthand for:package Mule; use base ("Horse", "Donkey"); # declare superclasses except that use base also takes into account any use fields declarations.package Mule; BEGIN { our @ISA = ("Horse", "Donkey"); require Horse; require Donkey; } Sometimes folks are surprised that including a class in @ISA doesn't require the appropriate module for you. That's because Perl's class system is largely orthogonal to its module system. One file can hold many classes (since they're just packages), and one package may be mentioned in many files. But in the most common situation, where one package and one class and one module and one file all end up being pretty interchangeable if you squint enough, the use base pragma offers a declarative syntax that establishes inheritance, loads in module files, and accommodates any declared base class fields. It's one of those convenient diagonals we keep mentioning. See the descriptions of use base and use fields in Chapter 31, "Pragmatic Modules" for further details. 12.5.2. Accessing Overridden MethodsWhen a class defines a method, that subroutine overrides methods of the same name in any base classes. Imagine that you've a Mule object (which is derived from class Horse and class Donkey), and you decide to invoke your object's breed method. Although the parent classes have their own breed methods, the designer of the Mule class overrode those by supplying the Mule class with its own breed method. That means the following cross is unlikely to be productive: Now suppose that through the miracle of genetic engineering, you find some way around a mule's notorious sterility problem, so you want to skip over the nonviable Mule::breed method. You could call your method as an ordinary subroutine, being sure to pass the invocant explicitly:$stallion = Horse->new(gender => "male"); $molly = Mule->new(gender => "female"); $colt = $molly->breed($stallion); However, this sidesteps inheritance, which is nearly always the wrong thing to do. It's perfectly imaginable that no Horse::breed subroutine exists because both Horses and Donkeys derive that behavior from a common parent class called Equine. If, on the other hand, you want to specify that Perl should start searching for a method in a particular class, just use ordinary method invocation but qualify the method name with the class:$colt = Horse::breed($molly, $stallion); Occasionally, you'll want a method in a derived class to act as a wrapper around some method in a base class. The method in the derived class can itself invoke the method in the base class, adding its own actions before or after that invocation. You could use the notation just demonstrated to specify at which class to start the search. But in most cases of overridden methods, you don't want to have to know or specify which parent class's overridden method to execute.$colt = $molly->Horse::breed($stallion); That's where the SUPER pseudoclass comes in handy. It lets you invoke an overridden base class method without having to specify which class defined that method.[6] The following subroutine looks in the current package's @ISA without making you specify particular classes: The SUPER pseudopackage is meaningful only when used inside a method. Although the implementer of a class can employ SUPER in their own code, someone who merely uses a class's objects cannot.package Mule; our @ISA = qw(Horse Donkey); sub kick { my $self = shift; print "The mule kicks!\n"; $self->SUPER::kick(@_); }
SUPER does not always work as you might like when multiple inheritance is involved. As you'd expect, it follows @ISA just as the regular inheritance mechanism does: in left-to-right, recursive, depth-first order. If both Horse and Donkey had a speak method, and you preferred the Donkey method, you'd have to name that parent class explicitly: More elaborate approaches to multiple inheritance situations can be crafted using the UNIVERSAL::can method described in the next section. Or you can grab the Class::Multimethods module from CPAN, which provides many elaborate solutions, including finding the closest match instead of leftmost one.sub speak { my $self = shift; print "The mule speaks!\n"; $self->Donkey::speak(@_); } Every bit of code in Perl knows what its current package is, as determined by the last package statement. A SUPER method consults the @ISA only of the package into which the call to SUPER was compiled. It does not care about the class of the invocant, nor about the package of the subroutine that was called. This can cause problems if you try to define methods in another class by merely playing tricks with the method name: package Bird; use Dragonfly; sub Dragonfly::divebomb { shift->SUPER::divebomb(@_) } Unfortunately, this invokes Bird's superclass, not Dragonfly's. To do what you're trying to do, you need to explicitly switch into the appropriate package for the compilation of SUPER as well: As this example illustrates, you never need to edit a module file just to add methods to an existing class. Since a class is just a package, and a method just a subroutine, all you have to do is define a function in that package as we've done here, and the class suddenly has a new method. No inheritance required. Only the package matters, and since packages are global, any package can be accessed from anywhere in the program. (Did we mention we're going to install a jacuzzi in your living room next week?)package Bird; use Dragonfly; { package Dragonfly; sub divebomb { shift->SUPER::divebomb(@_) } } 12.5.3. UNIVERSAL: The Ultimate Ancestor ClassIf no method definition with the right name is found after searching the invocant's class and all its ancestor classes recursively, one more check for a method of that name is made in the special predefined class called UNIVERSAL. This package never appears in an @ISA, but is always consulted when an @ISA check fails. You can think of UNIVERSAL as the ultimate ancestor from which all classes implicitly derive. The following predefined methods are available in class UNIVERSAL, and thus in all classes. These all work regardless of whether they are invoked as class methods or object methods.
The methods in UNIVERSAL are built-in Perl subroutines, which you may call if you fully qualify them and pass two arguments, as in UNIVERSAL::isa($formobj, "HASH"). (This is not recommended, though, because can usually has the answer you're really looking for.) You're free to add your own methods to class UNIVERSAL. (You should be careful, of course; you could really mess someone up who is expecting not to find the method name you're defining, perhaps so that they can autoload it from somewhere else.) Here we create a copy method that objects of all classes can use if they've not defined their own. (We fail spectacularly if invoked on a class instead of an object.) This Data::Dumper strategy doesn't work if the object contains any references to subroutines, because they cannot be properly reproduced. Even if the source were available, the lexical bindings would be lost.use Data::Dumper; use Carp; sub UNIVERSAL::copy { my $self = shift; if (ref $self) { return eval Dumper($self); # no CODE refs } else { confess "UNIVERSAL::copy can't copy class $self"; } } 12.5.4. Method AutoloadingNormally, when you call an undefined subroutine in a package that defines an AUTOLOAD subroutine, the AUTOLOAD subroutine is called in lieu of raising an exception (see the section Section 12.2, "Autoloading" in Chapter 10, "Packages"). With methods, this works a little differently. If the regular method search (through the class, its ancestors, and finally UNIVERSAL) fails to find a match, the same sequence is run again, this time looking for an AUTOLOAD subroutine. If found, this subroutine is called as a method, with the package's $AUTOLOAD variable set to the fully qualified name of the subroutine on whose behalf AUTOLOAD was called. You need to be a bit cautious when autoloading methods. First, the AUTOLOAD subroutine should return immediately if it's being called on behalf of a method named DESTROY, unless your goal was to simulate DESTROY, which has a special meaning to Perl described in the section Section 12.6, "Instance Destructors" later in this chapter. Second, if the class is providing an AUTOLOAD safety net, you won't be able to use UNIVERAL::can on a method name to check whether it's safe to invoke. You have to check for AUTOLOAD separately:sub AUTOLOAD { return if our $AUTOLOAD =~ /::DESTROY$/; ... } Finally, under multiple inheritance, if a class inherits from two or more classes each of which has an AUTOLOAD, only the leftmost will ever be triggered, since Perl stops as soon as it finds the first AUTOLOAD.if ($obj->can("methname") || $obj->can("AUTOLOAD")) { $obj->methname(); } The last two quirks are easily circumvented by declaring the subroutines in the package whose AUTOLOAD is supposed to manage those methods. You can do this either with individual declarations: or with the use subs pragma, which is more convenient if you have many methods to declare:package Goblin; sub kick; sub bite; sub scratch; Even though you've only declared these subroutines and not defined them, this is enough for the system to think they're real. They show up in a UNIVERAL::can check, and, more importantly, they show up in step 2 of the search for a method, which will never progress to step 3, let alone step 4.package Goblin; use subs qw(kick bite scratch); "But, but," you exclaim, "they invoke AUTOLOAD, don't they?" Well, yes, they do eventually, but the mechanism is different. Having found the method stub via step 2, Perl tries to call it. When it is discovered that the method isn't all it was cracked up to be, the AUTOLOAD method search kicks in again, but this time, it starts its search in the class containing the stub, which restricts the method search to that class and its ancestors (and UNIVERSAL). That's how Perl finds the correct AUTOLOAD to run and knows to ignore AUTOLOADs from the wrong part of the original inheritance tree. 12.5.5. Private MethodsThere is one way to invoke a method so that Perl ignores inheritance altogether. If instead of a literal method name, you specify a simple scalar variable containing a reference to a subroutine, then the subroutine is called immediately. In the description of UNIVERSAL->can in the previous section, the last example invokes all overridden methods using the subroutine's reference, not its name. An intriguing aspect of this behavior is that it can be used to implement private method calls. If you put your class in a module, you can make use of the file's lexical scope for privacy. First, store an anonymous subroutine in a file-scoped lexical: Later on in the file, you can use that variable as though it held a method name. The closure will be called directly, without regard to inheritance. As with any other method, the invocant is passed as an extra argument.# declare private method my $secret_door = sub { my $self = shift; ... }; This enables the file's own subroutines (the class methods) to invoke a method that code outside that lexical scope cannot access.sub knock { my $self = shift; if ($self->{knocked}++ > 5) { $self->$secret_door(); } } Copyright © 2001 O'Reilly & Associates. All rights reserved. |
|