tags:

views:

132

answers:

5

Lets say you have a parent Perl class in one file:

#!/usr/bin/perl
package Foo;
use strict;
use warnings;

use Data::Dumper;

sub new{
    my $class = shift;
    my %self = ();
    return bless %self, $class;
}
1;

and a subclass in a different file:

#!/usr/bin/perl
package Bar;
use base "Foo";
1;

Will the subclass inherit the use statements from the parent? I know the method new will be inherited.

Basically I am trying to reduce the amount of boilerplate in my code and I can't find a clear answer to this question.

A: 

You can get a definitive answer by examining the symbol tables for each package:

# examine-symbol-tables.pl
use Bar;

%parent_names = map{$_ => 1} keys %Foo::;
%child_names = map{$_ => 1} keys %Bar::;

delete $parent_names{$_} && ($common_names{$_} = delete $child_names{$_}) foreach keys %child_names;

print "Common names in symbol tables:\n";
print "@{[keys %common_names]}\n\n";

print "Unique names in Bar symbol table:\n";
print "@{[keys %child_names]}\n\n";

print "Unique names in Foo symbol table:\n";
print "@{[keys %parent_names]}\n\n";

$ perl inherit.pl
Common names in symbol tables:
BEGIN

Unique names in Bar symbol table:
ISA isa import

Unique names in Foo symbol table:
Dumper new VERSION
mobrule
+3  A: 

Ah, good question!

Will the subclass inherit the use statements from the parent? 

Well this depends on what you mean by inherit. I won't make any assumptions until the end, but the answer is maybe. You see, perl mixes the ideas of Classes, and Namespaces -- a package is a term that can describe either of them. Now the issue is the statement use all it does is force a package inclusion, and call the targets import() sub. This means it essentially has unlimited control over your package - and by way of that your class.

Now, compound this with all methods in perl being nothing more than subs that take $self as a first argument by convention and you're left with perl5. This has an enormous upside for those that know how to use it. While strict is a lexical pragma, what about Moose?

package BigMooseUser;
use Moose;

package BabyMooseUser;
our @ISA = 'BigMooseUser';

package Foo;
my $b = BabyMooseUser->new;
print $b->meta->name;

Now, where did BabyMooseUser get the constructor (new) from? Where did it get the meta class from? All of this is provided from a single use Moose; in the parent class (namespace). So

Will the subclass inherit the use statements from the parent?

Well, here, in our example, if the effects of the use statement are to add methods, than certainly.

This subject is kind of deep, and it depends if you're talking about pragmas, or more obscure object frameworks, or procedural modules. If you want to mitigate a parents namespace from affecting your own in the OO paradigm see namespace::autoclean.

Evan Carroll
Actually, use doesn't force a package inclusion. It looks for a file based on the package name that you want to use(). That file doesn't have to load that package. By convention we name our files with the package name it contains, but that's not something use() cares about. For instance, Module::Build::Version is really there to load version. The file use() loads might even have more than one package.
brian d foy
BabyMooseUser gets its new() because you declare an inheritance relationship. The single Moose call doesn't set that up for you. And, autoclean is only going to deal with imported symbols. It's not going to restrict access to anything else you want to get at.
brian d foy
It's kinda weird to say that methods are subs that *take* $self as a first argument. Methods are subs, but you end up with their referent as the first argument without explicitly specifying it as an argument. That referent might be the class name (a string) or a reference to an object, depending on what's to the left of the -> (ignoring indirect calls). It's also not as simple as looking for literals or variables on the left side. :)
brian d foy
@brian d foy, I think I made that all amply clear `All of this is provided from a single use Moose; in the parent class (namespace).` the inheritance relationship was understood in the question *parent perl class*. If you don't feel the verbiage is clear enough, or you want to add content to my answer that isn't present in your own, use the edit button.
Evan Carroll
You think it is better -- but mine the poster thinks is better. I'll take mine. You seem to want to argue incessantly and side track answers to no avail on technical minutiae that isn't really what the question is getting at. I'm just going to ignore you.
Evan Carroll
+2  A: 

For boilerplate reduction, I have a couple of strategies: Most of my classes are Moose classes, which takes care of OO setup and also gives me strict and warnings. If I want to have functions available in many packages, I'll create a project specific MyProject::Util module that uses Sub-Exporter to provide me with my own functions and my own interface. This makes it more consistent, and if I decide to change the Dumper (for example) later for whatever reason, I don't have to change lots of code. That'll also allow you to group exports. A class then usually looks something like this:

package Foo;
use Moose;
use MyProject::Util qw( :parsing :logging );

use namespace::autoclean;

# class implementation goes here

1;

If there's other things you regard as boilerplate and want to make simpler to include, it of course depends on what those things are.

phaylon
+5  A: 

You asked in a comment about Test::Most and how it reduces boilerplate. Look at it's import method. It's loading the modules into its namespace, adding those symbols to @EXPORT, then re-calling another import through a goto to finally get them into the calling namespace. It's some serious black magic that Curtis has going on there, although I wonder why he just didn't use something like import_to_level. Maybe there are some side effects I'm not thinking about.


I talk quite a bit about this sort of thing in Avoid accidently creating methods from module exports in The Effective Perler. It's in a different context but it's some of the same issues.

Here's a different example.

If some other module loads a module, you have access to it. It's not good to depend on that though. Here are three separate files:

Top.pm

use 5.010;

package Top;
use File::Spec;

sub announce { say "Hello from top!" }
1;

Bottom.pm

package Bottom;
use parent qw(Top);

sub catfiles { File::Spec->catfile( @_ ) }

1;

test.pl

use 5.010;

use Bottom;

say Bottom->catfiles( qw(foo bar baz) );

say File::Spec->catfile( qw( one two three ) );

I only load File::Spec in Top.pm. However, once loaded, I can use it anywhere in my Perl program. The output shows that I was able to "use" the module in other files even though I only loaded it in one:

Bottom/foo/bar/baz
one/two/three

For this to work, the part of the code that loads the module has to load before any other part of the code tries to use that module. As I said, it's a bad idea to depend on this: things break if the loading sequence changes or the loading module disappears.

If you want to import symbols, however, you have to explicitly load the module you want while you are in the package you want to import into. That's just so the exporting module defines the symbols in that package. It's not something that depends with scope.

brian d foy
+1  A: 

A pragmatic answer to your problem: Either use, or look at how Modern::Perl does it to enforce strict and warnings.

nicomen
Modern::Perl pulls in strict and warnings, which are modules that futz with $^H. Most modules aren't going to want to do that.
brian d foy