To understand this you need to understand how Perl handles circular
dependencies.

When we execute code that loads other code (for instance use at
compile time, require at run time, or a variety of things in Moose),
Perl will mark the current package as incompletely loaded then go off
and try to load the other one.  If curing that load, Perl is told to
load your package, Perl will skip that step to avoid infinite
recursion.  Therefore the other package will continue loading with
some of its dependencies not completely loaded.

The result can be exactly what you are seeing.  One of the packages
tries to load with the other one incompletely there.

Here are three possible fixes in roughly the order that I would try them.

1. Remove the circular dependency.  (Always, always, always best if
you can manage it.)

2. Figure out what order you have to load things in order to avoid
breakage, and do that consistently.  (I've been known to introduce a
new package to load just to make sure it happens correctly.)

3. Move the code that is needed by circular dependencies so that it is
present before whatever will load the circular dependency.  (Add big
fat comments and unit tests around this issue.  Because it will seem
like black magic and it is easy to break it.)

On Wed, Feb 25, 2015 at 12:30 PM, Daniel Hermann
<daniel.herm...@1und1.de> wrote:
> Hi,
>
> I have two classes Test1 and Test2, both consuming the role
> TestRole which uses another class TestGlue, which in turn uses
> Test1 and Test2 internally.
>
> My main program uses Test1 and Test2 and runs into a Moose error
> when it calls a method in Test2 provided by TestRole:
>
>    Can't locate object method "load_role" via package "Test2" at Test2.pm
> line 5.
>
> What is going wrong here?
>
> This is the full code:
>
> === TestRole.pm ===
> package TestRole;
> use Moose::Role;
> use TestGlue ();
>
> sub load_role {}
>
> 1;
> ==============
>
> === Test1.pm =====
> package Test1;
> use Moose;
> with "TestRole";
>
> sub load{ shift->load_role }
>
> 1;
> ==============
>
> === Test2.pm =====
> package Test2;
> use Moose;
> with "TestRole";
>
> sub load{ shift->load_role }
>
> 1;
> ==============
>
> === TestGlue.pm ===
> package TestGlue;
> use Moose;
> use Test1 ();
> use Test2 ();
>
> 1;
> ==============
>
> === main.pl =====
> #!/usr/bin/env perl
> use Test1 ();
> use Test2 ();
>
> Test1->new->load;
> Test2->new->load;
>
> 1;
> ==============
>
>
> The above code works if
>
> - I do not 'use Test2' in TestGlue.pm or
> - I use an eval block in main.pl such as
>
>     eval { use Test2; Test2->new->load; };
>
> It seems to me that the import of the class Test2 in "role context"
> via TestGlue.pm, triggered by 'use Test1' in main.pl, is incomplete
> somehow, and the second import via 'use Test2' in main.pl does
> not compensate this.
>
> Thanks for any hints,
> Daniel
>
> --
> Daniel Hermann
>
> Operations Developer
> 1&1 Internet AG
>

Reply via email to