On Apr 9, 2012, at 7:31 AM, Stevan Little wrote: > On Apr 9, 2012, at 3:58 AM, Ovid wrote: > >>> ________________________________ >>> From: Jesse Luehrs <[email protected]> >>> >>> 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
This might be a case worth documenting, though, if nothing more than to point out why this is necessary. That is, unless an example already exists... chris
