8.6 Overriding the Methods


8.6 Overriding the Methods

Let's add a mouse that can barely be heard :

 { package Animal;   sub speak {     my $class = shift;     print "a $class goes ", $class->sound, "!\n";   } } { 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, Mouse has its own speaking routine, so Mouse->speak doesn't immediately invoke Animal->speak . This is known as overriding . You use overriding to shadow the method in the derived class ( Mouse ) because you have a specialized version of the routine, instead of calling the more general base class's method (in Animal ). In fact, you didn't even need to initialize @Mouse::ISA to say that a Mouse was an Animal at all because all the methods needed for speak are defined completely with Mouse .

You've now duplicated some of the code from Animal->speak ; this can be a maintenance headache . For example, suppose someone decides that the word goes in the output of the Animal class is a bug. Now the maintainer of that class changes goes to says . Your mice will still say goes , which means the code still has the bug. The problem is that you invoked cut and paste to duplicate code, and in OOP, that is a sin. You should reuse code through inheritance, not by cut and paste.

How can you avoid that? Can you say somehow that a Mouse does everything any other Animal does, but add in the extra comment? Sure!

As your first attempt, you can invoke the Animal::speak method directly:

 { package Animal;   sub speak {     my $class = shift;     print "a $class goes ", $class->sound, "!\n";   } } { 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 because you've stopped using the method arrow, you have to include the $class parameter (almost surely the value of " Mouse ") as the first parameter to Animal::speak ,.

Why did you stop using the arrow? Well, if you invoke Animal->speak there, the first parameter to the method is " Animal, " not " Mouse ", and when the time comes for it to call for the sound , it won't have the right class to select the proper methods for this object.

Invoking Animal::speak directly is a mess, however. What if Animal::speak didn't exist before and was inherited from a class mentioned in @Animal::ISA ? For example, suppose the code was:

 { package LivingCreature;   sub speak { ... }   ... } { package Animal;   @ISA = qw(LivingCreature);   # no definition for speak(  )   ... } { package Mouse;   @ISA = qw(Animal);   sub speak {     ...     Animal::speak(  ... );   }   ... } 

Because you no longer use the method arrow, you get one and only one chance to hit the right subroutine. You'll look for it in Animal , and not find it, and the program aborts.

The Animal classname is now hardwired into the subroutine selection. This is a mess if someone maintains the code, changing @ISA for Mouse , and didn't notice Animal there in speak . Thus, this is probably not the right way to go.



Learning Perl Objects, References & Modules
Learning Perl Objects, References, and Modules
ISBN: 0596004788
EAN: 2147483647
Year: 2003
Pages: 199

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net