develooper Front page | perl.moose | Postings from April 2012

Re: Role composition bug?

Thread Previous | Thread Next
From:
Fields, Christopher J
Date:
April 9, 2012 07:04
Subject:
Re: Role composition bug?
Message ID:
63B1F851-913A-4135-BA6C-6DAF740AC1FF@illinois.edu
On Apr 9, 2012, at 7:31 AM, Stevan Little wrote:

> On Apr 9, 2012, at 3:58 AM, Ovid wrote:
> 
>>> ________________________________
>>> From: Jesse Luehrs <doy@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

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



Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About