When should I use `use`?
As long as I can remember, whenever I use a module I include a use
line at the beginning of my code.
Recently I was writing two Moose object modules that use each other. Look at this over-simplistic example:
One module:
package M1 0.001;
use Moose;
use 5.010;
use namespace::autoclean;
# use M2; ### SEE QUESTION BELOW
has 'name' => (
is => 'ro',
isa => 'Str',
required => 1,
);
has 'very_cool_name' => (
is => 'ro',
lazy => 1,
builder => '_build_very_cool_name',
);
sub _build_very_cool开发者_JS百科_name {
my ($self) = @_;
my $m2 = M2->new( m1 => $self );
return 'very ' . $m2->cool_name();
}
__PACKAGE__->meta->make_immutable;
1;
Another module: package M2 0.001;
use Moose;
use 5.010;
use Data::Dumper; # TODO DEBUG REMOVE
use namespace::autoclean;
use M1;
has 'm1' => (
is => 'ro',
isa => 'M1',
required => 1,
);
sub cool_name {
my ($self) = @_;
return 'cool ' . $self->m1->name();
}
__PACKAGE__->meta->make_immutable;
1;
And a short example that uses them:
use strict;
use warnings;
use 5.010;
use M1;
use M2;
my $m1 = M1->new(name => 'dave');
say $m1->very_cool_name();
Now, note the two modules use each other. M1
creates an instance of M2
and use it to generate very_cool_name
, while M2
has an instance of M1
as an attribute.
Now, if I uncomment use M2;
in M1
my eclipse goes mad. I guess it's because this a the loop created by this 'circular use`.
I commented this use
and everything seems to works fine (I think...), but makes me really anxious (I'm using an object without use
-ing its class! Is that 'legal'?..). This also which made me wonder:
When do I really need to use
use
? I think that I was taught to always use it, and surely when I use an object.Is there anything fundamentally wrong when two modules use each other (in the sense that each uses an object of the other module; I know there some cases where this is logically impossible, but sometimes - as in this case - I think it does make sense).
From a Perl perspective it's fine. use
is smart enough to recognize that a module has already been loaded and not load it again. That said, the faint whiff of code smell should make you think about whether mutual dependency is acceptable or if you should refactor your code to eliminate it.
Eclipse, apparently, is not quite as bright. Commenting out one of the use
statements to placate the editor will probably work but could create subtle bugs depending on the order the modules are loaded in (by the application) and when they use each others functionality. e.g. if M1 were loaded first, didn't use M2
, and had a BEGIN
block that needed functionality from M2... boom! If nothing happens until runtime (which is likely) you should be okay.
While it isn't an issue here, you'd also have problems if your use
imported symbols from the other package. In that case couldn't remove the use
without changing your code to fully qualify all references. (e.g. call MyModule::function()
instead of just function()
)
There's no reason for M2 to use M1
. You don't actually have a recursive dependency.
All M2 does is validate some object's classname -- which doesn't require having loaded M1 -- and call a method on it -- which means whoever constructed that object loaded M1.
Your rule about needing to use
a class in order to call methods on an object of that class is wrong. use
a class when you're going to call methods on the it directly -- for example, new
. (This assumes pure OO modules, obviously, not things that export functions/symbols.)
Consider polymorphism. It is a feature that I can make my own subclass of M1 (called, say, M1A) and pass it to M2 without M2 having to know anything about the existence of M1A.
精彩评论