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


Reply via email to