Search code examples
perlperl-modulemoose

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_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).


Solution

  • 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.