6

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?

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • 5
    The `base` and `parent` modules allow you to establish ISA relationships at compile time. By contrast, modifying `@ISA` yourself happens at run time. In this light, one way to rephrase your question is like this: Is it generally advantageous to establish inheritance earlier (compile-time) rather than later, and if so why? Also see these related questions: http://stackoverflow.com/questions/1378309/whats-the-difference-between-use-base-and-isa-in-perl/1379276 and http://stackoverflow.com/questions/876471/what-is-the-difference-between-parent-and-base-in-perl-5. – FMc Feb 13 '10 at 14:27
  • 2
    `BEGIN { @ISA = ... };` also happens at compile-time. – friedo Feb 13 '10 at 14:36
  • @FM Thanks for comment :-) I rephrased the question – Eugene Yarmash Feb 13 '10 at 14:37

3 Answers3

5
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'; }

mtmk
  • 6,176
  • 27
  • 32
  • 3
    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 Feb 13 '10 at 13:03
  • I'm too rusty in Perl to know more about 'parent'. Thanks @Leon +1 – mtmk Feb 13 '10 at 15:32
  • 1
    The `base` module will work when the parent class is in the same file. See http://search.cpan.org/perldoc?base. – FMc Feb 13 '10 at 17:16
  • 1
    Leon: parent is in core. It just hasn't been for as long as base. – tsee Feb 14 '10 at 09:34
  • @FM: as will parent, only you have to be explicit about your intent – ysth Feb 14 '10 at 12:09
3

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
  • 153,029
  • 25
  • 195
  • 336
1

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
  • 5,034
  • 1
  • 19
  • 27