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?
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?
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:
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'; }
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
.
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.