in reply to moose role that uses a class that does the role

In Hello.pm, you can change use Greeting to require Greeting, and then all should be well.

Another fix would be to swap the two use lines in test.pl

The reason this problem occurs is as follows.

  1. perl loads test.pl; it encounters use Greeting2.
  2. perl loads and compiles Greeting2.pm with no problems. Then with 'Hello' gets executed.
  3. Moose::with loads Hello.pm.

Now we've got to look at what happens during the compilation stage of Hello.pm. This is when use and BEGIN things are executed, but not other stuff. In particular, no subs have been defined within the Hello package yet!

  1. perl encounters use Greeting.
  2. perl loads and compiles Greeting.pm with no problems. Then with 'Hello' gets executed.
  3. Moose says to itself, "the Hello role has already been loaded, I don't need to load it again".
  4. Moose copies all methods defined in the Hello role into the Greeting class. But, as we established before stage 4, there are not any subs in Hello yet!

... and the rest of the load process is uninteresting.

Changing use Greeting to require Greeting in Hello.pm fixes things because it forces that step 4 to happen a little later, after Hello has been fully compiled.

See also: leaky abstraction.

Update: as a general principle, for "cross-loading" between classes and roles within the same "clan" (i.e. collection of modules written for a particular project), I'd recommend loading them at run time instead of compile time. That means load them with require rather than use; or load them with Class::Load (which is one of Moose's dependencies, so you've already got it!); or rely on the fact that with and extends automatically load their argument. This advice only applies to classes and roles within the clan; not to pragmata, exporters, third-party classes, etc.

perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'