Inheritance

[ Perl tips index ]
[ Subscribe to Perl tips ]

One of the most compelling reasons to learn and use Object Oriented Perl is the ability to extend existing classes through inheritance.

What is inheritance?

Inheritance allows us to take an existing Perl module or class, and extend it to provide new features. Put very simply, inheritance is a way of saying ``I want to do everything this module can do, but I'd like to do these things differently.''

For example, you may have a database, and a number of queries that you'd like to execute during off-peak times. Rather than needing to change existing programs to check the time, or call a new function that schedules the work, you can instead make a sub-class of DBI. Your new DBI::OffPeak will look and feel like the regular DBI class in every way, except it can schedule queries to run during your off-peak sessions.

Sub-classes are easy to integrate into existing programs that already use their parent classes, often requiring only a couple of lines of change at most. This is a huge win for keeping code maintainable.

The parent code is not modified in any way. If we're using a module from CPAN, and provided that we've subclassed correctly, then we can continue to take advantage of any bugfixes or new features that may be released.

When should I inherit?

Anytime you find an existing Perl module or class that does almost what you want, you have an excellent candidate for inheritance. You can subclass Net::LDAP to understand your LDAP directory. You can subclass LWP::UserAgent or WWW::Mechanize to understand your local intra-net and search for information accordingly.

How do I inherit?

When Perl goes looking for a method (a subroutine called on an object or class) it first looks for it in the child or derived class. If it can't be found, then Perl looks for a special array called @ISA. The contents of the @ISA array is interpreted as a list of parent classes, and these will be searched for the method. Perl allows for multiple-inheritance, and in such circumstances the left-most ancestor always takes precedence.

As an example, we'll write a module to interrogate our intra-net for information. We'll call it ``PTA::IntraNet'' (the PTA standing for Perl Training Australia):

        package PTA::IntraNet;
        use WWW::Mechanize;
        our @ISA = qw(WWW::Mechanize);
        1;      # End of file.

Once we've done this, our PTA::IntraNet class can do everything that WWW::Mechanize can do. Object creation is done using the standard process of:

        #!/usr/bin/perl -w 
        use strict;
        use PTA::IntraNet;
        my $agent = PTA::IntraNet->new;

So far our new class is very dull, since it doesn't do anything extra. Let's change that. First we'll add a 'home' method, that takes our agent to our homepage:

        package PTA::IntraNet;
        use WWW::Mechanize;
        our @ISA = qw(WWW::Mechanize);
        sub home {
                my ($this) = @_;
                return $this->get("http://perltraining.com.au/");
        }
        1;      # End of file.

Now we can use $agent->home() to automatically navigate to our homepage.

If we want to have the ability to easily look up information on a particular course, based upon its name, we might write:

        sub course {
                my ($this, $name) = @_;
                $this->home;               # Navigate home.
                $this->follow("Courses");  # Find our courses page.
                # Now find the course we're after.
                return $this->follow($name);
        }

This allows us to write application code as follows:

        $agent->course("Obj Oriented Perl");
        print $agent->content();

and have our agent automatically find the correct page and display its contents.

From here we can add further Perl Training Australia specific methods when we need them. These might include methods which extract requested information rather than returning the whole web page, or use other data sources to fulfil requests.

use base as a short-cut

In our above code we had to both use the module and add it to our @ISA array. This can introduce strange errors if you forget one of these steps. A more concise option is to use the base pragma.

        package PTA::IntraNet;
        use base qw(WWW::Mechanize);
        # Some useful methods
        1;      # End of file.

In almost all cases, using the base pragma is equialent to manually using the module and setting @ISA yourself. Both methods are commonly seen for inheritance.

Want to learn more?

To learn more about inheritance in Perl, read Dr Damian Conway's book: Object Oriented Perl. To learn more about Perl's OO model and how to write OO Perl code, join us on one of our upcoming Object Oriented Perl training courses.

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS