views:

157

answers:

3

AFAIK inheritance in Perl is usually set up like this:

package Mule;
our @ISA = ("Horse", "Donkey");

Are there any examples where use base (or use parent) is better instead?

+5  A: 
use base qw(Horse Donkey);

This is roughly equivalent to:

BEGIN {
    require Horse;
    require Donkey;
    push @ISA, qw(Horse Donkey);
}

It is tidier if you need to load the modules code as well as inheriting from them. BTW, there are issues with multiple inheritance, but thats a different question :)

Edit: Compile-time v. run-time advantages:

  • You have the safety of the compile-time check with use base meaning your script won't even start if your base module is not present on the filesystem.
  • If you want to decide to use a given module at run-time, then you can test and add the module to your parents:

    if (eval { require X }) { push @ISA, 'X'; }

Maxwell Troy Milton King
You can use use parent qw(base classes) or use base qw(base classes). parent is preferable over base because it has a lot less dark magic, but it isn't in core like base.
Leon Timmermans
I'm too rusty in Perl to know more about 'parent'. Thanks @Leon +1
Maxwell Troy Milton King
The `base` module will work when the parent class is in the same file. See http://search.cpan.org/perldoc?base.
FM
fixed thanks. +1 @FM
Maxwell Troy Milton King
Leon: parent is in core. It just hasn't been for as long as base.
tsee
@FM: as will parent, only you have to be explicit about your intent
ysth
A: 

Regarding compile-vs-run-time:

In Perl, modules (packages/namespaces) usually live in separate files. I.e. Some::Module would be find in Some/Module.pm. In this setup, the compile-vs-run-time difference won't matter much. The run-time of the module you load via use() will be before the compile-time of the calling code continues. Observer:

File Some/Module.pm:

package Some::Module;
BEGIN{ print "Some::Module - compile time\n" }
print "Some::Module - run time\n";
1;

File test.pl:

BEGIN{ print "Just started compiling the program.\n" }
use Some::Module;
BEGIN{ print "main - compile time\n" }
print "main - run time\n";

The output will be:

Just started compiling the program.
Some::Module - compile time
Some::Module - run time
main - compile time
main - run time

Therefore, an our @ISA = qw(Base); will be executed before the compilation of your main program continues after loading the module.

It is correct, however, that assigning to @ISA does not ensure that the base class has been loaded. That is why we have the use base and use parent pragmas. If you do not specifically need any features of use base (fields) nor require the longer backwards compatibility that it provides over use parent, I suggest you use the more light-weight use parent.

tsee
+3  A: 

Establishing inheritance at compile time avoids a particularly hard to debug dependency loop, illustrated below.

# Child.pm
package Child;

our @ISA = qw(Mother);

use Foo;

# Mother.pm
package Mother;

sub wibble { 42 }

# Foo.pm
package Foo;

use Child;
Child->wibble;

If you "use Child" before "use Foo" then Foo will try to call Child->wibble before its established its inheritance on Mother. If instead Child were to use parent qw(Mother) its inheritance would be established before it tried to load anything else.

I've been this sort of dependency loop in private, corporate code that tends to be a bit more intertwined than public code. It sucks to debug, which is why I'd recommend always establishing inheritance at compile-time.

Schwern
Thanks, that's a useful illustration.
FM