Item 51: Inherit data explicitly.


As mentioned earlier, Perl has no built-in facilities for data inheritance. By and large, this isn't a problem at all. Consider the following:

  • Perl objects do not have predeclared members or sizes. Typically, Perl objects are represented using references to anonymous hashes. The members of an object are key-value pairs in a hash. There is no need for a member to be declared, and consequently there is no need for a subclass to inherit declarations from a parent class.

  • Perl constructors are inheritable and can be very "thin" and general. A single parent class constructor can serve the needs of a whole family of derived classes. (See the " generic, inheritable" constructor immediately below.)

Let's look at a simple class hierarchy:

 package Person;  sub new {    my $pkg = shift;    bless { @_ }, $pkg;  } 

The basic generic, inheritable constructor.

 package Student;  @ISA = qw(Person); 

A subclass of Person , inheriting Person 's constructor.

 $joseph = new Person(    first => 'Joseph',    last => 'Hall'  ); 

Create a new Person .

 $merlyn = new Student(    first => 'Randal',    last => 'Schwartz',    id => 7777  ); 

Create a new Student by inheriting Person::new .

Because of the way Perl works, in many cases there is no requirement for any kind of data inheritance. Objects have the members they are assigned. Their class is irrelevant.

Data inheritance and complex constructors

When constructors become more complex, however, some form of data inheritance may be necessary. A good example is when subclass constructors add default values for some members. Let's consider a class hierarchy of objects representing shapes in a graphics windowcircles, rectangles, polygons, text, and so on. Generally, a hierarchy like this is derived from a single parent classwe will call ours Graphic . Suppose the Graphic constructor sets some default values for line width and color :

The Graphic class

 package Graphic; 
 
 sub new {    my $pkg = shift;    bless {      pen => 1,      color => 'black',      @_    }, $pkg;  } 

A generic constructor for Graphic objects.

Supply some default values for members in case they are not supplied in @_ .

Now, suppose we want to derive a class, Text , from Graphic . Our constructor for Text also will need to set some default values, but these will be peculiar to Text objects. We will have to write the constructor for Text objects so that it invokes the Graphic constructor. However, we also have to be careful to write it so that the constructed object gets the Text default values. It must also wind up blessed into class Text :

The Text class

This example defines a constructor for Text , a subclass of Graphic . The constructor would be called like this:

 $text = new Text (color => 'blue', font => 'courier'); 
 package Text; 
 
 @ISA = qw(Graphic); 

Subclass of Graphic .

 sub new {    my $pkg = shift;    SUPER::new $pkg (      font => 'times',      size => 12,      @_ );  } 

Call superclass constructor, passing in our own defaults.

The tricky part in this example is the way in which the Graphic constructor is called. SUPER::new $pkg () invokes the inherited constructor (see Item 50 for more information about SUPER ), but passes 'Text' , not 'Graphic' , as the constructor's class argument. You might be tempted to write a slightly simpler Text constructor, eschewing the fancy SUPER keyword:

The Text classthe wrong way

 package Text; 
 
 @ISA = qw(Graphic); 
 
 sub new {    my $pkg = shift;    new Graphic (      font => 'times',      size => 12,      @_ );  } 

Call the Graphic constructor but what class is the object?

This does the right thing by calling the parent class constructor, but unfortunately , this Text constructor creates and returns Graphic objects. You will have to re-bless them into Text at the end of the constructor:

 sub new {    my $pkg = shift;    bless new Graphic (      font => 'times',      size => 12,      @_ ), $pkg;  } 

Call the Graphic constructor but what class is $self now?

OK, make it a Text (or whatever).

This is okay, but you'll be better off using SUPER . Among other things, using SUPER::new means that you do not have to modify the subclass constructor if the name of the parent class changes.



Effective Perl Programming. Writing Better Programs with Perl
Effective Perl Programming: Writing Better Programs with Perl
ISBN: 0201419750
EAN: 2147483647
Year: 1996
Pages: 116

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