On Apr 9, 2012, at 3:58 AM, Ovid wrote: >> ________________________________ >> From: Jesse Luehrs <d...@tozt.net> >> >> On Sun, Apr 08, 2012 at 12:31:25PM -0700, Ovid wrote: >>> Hi all, >>> >>> I'm wondering if this is a known bug or a misunderstanding on my part (I >>> assume the latter): >>> >>> use 5.10.0; >>> { package Role::A; use Moose::Role; with 'Role::C'; } >>> { package Role::B; use Moose::Role; with 'Role::C'; } >>> { package Role::C; use Moose::Role; with 'Role::D'; } >>> { >>> package Role::D; >>> use Moose::Role; >>> >>> sub foo { >>> my $proto = shift; >>> my $class = ref $proto // $proto; >>> return "$class\::foo"; >>> } >>> } >>> package Consume; >>> use Moose; >>> with qw(Role::A Role::B); >>> say Moose->VERSION; >>> say Consume->foo; >>> >>> That prints out: >>> >>> 2.0402 >>> Can't locate object method "foo" via package "Consume" at roles.pl line >>> 19. >>> >>> Given that Role::C uses Role::D and the latter provides the 'foo()' method, >>> that method should be provided to both Role::A and Role::B since they each >>> consume Role::C. When consuming those roles, the Consume class should then >>> have the 'foo()' method, but it does not. >>> >>> Did I misunderstand something? (For the curious, my Role::Basic module has >>> the same bug). >> >> This is just a load order issue. 'with' happens at runtime, so when you >> say "with 'Role::C' in package Role::A, Role::C has no methods in it >> (since its "with 'Role::D'" hasn't executed yet). If you actually load >> things in the proper order, it just works (with no conflict, because all >> of the 'foo' methods are the same actual method). There is no bug here. > > > According to the definition of traits (I recognize that roles are similar to > traits, but not identical), traits guarantee associativity by definition. > That is to say: > > ( A + B ) + C = A + ( B + C ) > > Thus, it's absolutely a bug for traits to exhibit different behavior > depending on the order in which traits are defined or consumed. Since roles > are not traits, is this documented? > > > See also: http://scg.unibe.ch/archive/papers/Scha02cTraitsModel.pdf, section > 3.4, proposition 1.
Right, but what Jesse is saying is that given the constraints of the Perl world that Moose must live in you have to load stuff in the right order. Here is a version of your script that actually works. use 5.10.0; { package Role::D; use Moose::Role; sub foo { my $proto = shift; my $class = ref $proto // $proto; return "$class\::foo"; } } { package Role::C; use Moose::Role; with 'Role::D'; } { package Role::A; use Moose::Role; with 'Role::C'; } { package Role::B; use Moose::Role; with 'Role::C'; } package Consume; use Moose; with qw(Role::A Role::B); say Moose->VERSION; say Consume->foo; Jesse++ for stoping a second and thinking this one through. - Stevan