Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A12: Conflicting Attributes in Roles

6 views
Skip to first unread message

Jonathan Lang

unread,
Apr 21, 2004, 3:35:58 AM4/21/04
to Perl6
role A {has Cat $.x;}
role B {has Dog $.x;}
class Foo {does Cat; does Dog;}
my Foo $bar;
$bar.x; # Is this a Cat or a Dog?

=====
Jonathan "Dataweaver" Lang




__________________________________
Do you Yahoo!?
Yahoo! Photos: High-quality 4x6 digital prints for 25¢
http://photos.yahoo.com/ph/print_splash

Austin Hastings

unread,
Apr 21, 2004, 3:56:35 AM4/21/04
to Jonathan Lang, Perl6

> -----Original Message-----
> From: Jonathan Lang [mailto:datawe...@yahoo.com]
>
> role A {has Cat $.x;}
> role B {has Dog $.x;}
> class Foo {does Cat; does Dog;}
> my Foo $bar;
> $bar.x; # Is this a Cat or a Dog?

<A12>
If, however, two roles try to introduce a method of the same name (for some
definition of name), then the composition of the class fails, and the
compilation of the program blows sky high--we sincerely hope. It's much
better to catch this kind of error at compile time if you can. And in this
case, you can.
</A12>

Since classes are autogenerating accessors based in data members, it's
doubly reasonable to assume that the same solution will apply: conflict ->
death.

=Austin

Buddha Buck

unread,
Apr 21, 2004, 7:19:34 AM4/21/04
to perl6-l...@perl.org
Originally sent to Austin alone by accident....

From one C6PAN module:

role Dog {
has $.collar;
...
}

From another C6PAN module:

role LawEnforcementOfficer {
method arrest { ... }
...
}

From a third C6PAN module:

class PoliceDog does Dog does LawEnforcementOfficer { ... }

I use PoliceDog in my production code, without a problem. I don't use
the collar attribute (it's unimportant in my application).

The author of the LawEnforcementOfficer role does an upgrade that fixes
an important bug but also.....

role LawEnforcementOfficer {
method arrest { ... }
has $.collar; # for holding most recently arrested
...
}

So when my program fails to compile, who do I blame? How do I fix it
quickly, preferrably without creating local branches of the C6PAN modules?


>
> =Austin
>


Chromatic

unread,
Apr 21, 2004, 12:17:06 PM4/21/04
to Buddha Buck, p6l
On Wed, 2004-04-21 at 04:19, Buddha Buck wrote:

> From one C6PAN module:
>
> role Dog {
> has $.collar;
> ...
> }

> From a third C6PAN module:


>
> class PoliceDog does Dog does LawEnforcementOfficer { ... }

> role LawEnforcementOfficer {


> method arrest { ... }
> has $.collar; # for holding most recently arrested
> ...
> }
>
> So when my program fails to compile, who do I blame?

Whoever didn't read the documentation for the appropriate roles. :)

> How do I fix it
> quickly, preferrably without creating local branches of the C6PAN modules?

* Add a disambiguatey method to PoliceDog that dispatches
appropriately. (Insert handwavey "well you *could* do it this way or
you *might* do it that way.")

* Force the loading of a specific version of LawEnforcementOfficer.

-- c

Aaron Sherman

unread,
Apr 23, 2004, 11:04:22 AM4/23/04
to chromatic, Perl6 Language List
On Wed, 2004-04-21 at 12:17, chromatic wrote:

> * Add a disambiguatey method to PoliceDog that dispatches
> appropriately. (Insert handwavey "well you *could* do it this way or
> you *might* do it that way.")

I agree, but given that the average user should probably not have to
interact with the dispatching system just to say "my class uses class
a's foo, not class b's foo", can I suggest:

class a { method foo {...} }
class b { method foo {...} }
class c { does a; does b but a.foo; }

the "but" disarms the compilation failure that A12 introduced, but only
for that method. Every time you have such a conflict, you will have to
disarm in this way. What MIGHT be a problem is:

class c { does a but b.bar; does b but a.foo; }

which requires the compiler to accept b.bar even though it has not yet
seen the "does b". You could assert the other way around:

class c { does a for <<bar baz>>; does b for <<foo biz>>; }

which is kind of nifty looking, but some may blanch at the dual meaning
for "for"....

--
Aaron Sherman <a...@ajs.com>
Senior Systems Engineer and Toolsmith
"It's the sound of a satellite saying, 'get me down!'" -Shriekback


Brent 'Dax' Royal-Gordon

unread,
Apr 23, 2004, 11:44:18 AM4/23/04
to Aaron Sherman, chromatic, Perl6 Language List
Aaron Sherman wrote:
> seen the "does b". You could assert the other way around:
>
> class c { does a for <<bar baz>>; does b for <<foo biz>>; }
>
> which is kind of nifty looking, but some may blanch at the dual meaning
> for "for"....

Funny how similar that is to

class c { does a handles <<bar baz>>; does b handles <<foo biz>>; }

--
Brent "Dax" Royal-Gordon <br...@brentdax.com>
Perl and Parrot hacker

Oceania has always been at war with Eastasia.

Aaron Sherman

unread,
Apr 23, 2004, 11:57:45 AM4/23/04
to Brent 'Dax' Royal-Gordon, Perl6 Language List
On Fri, 2004-04-23 at 11:44, Brent 'Dax' Royal-Gordon wrote:

> Aaron Sherman wrote:

> > class c { does a for <<bar baz>>; does b for <<foo biz>>; }

> Funny how similar that is to


>
> class c { does a handles <<bar baz>>; does b handles <<foo biz>>; }

In "Relationship to Roles" A12 makes the point that delegation and roles
are not the same thing.

To tie them together with C<handles> MIGHT be wise and might not. I'll
have to think about that and see what others post on the topic.

I have not read the delegation section enough, either... something I
need to fix. It certainly seems powerful, as it merges the "has" and
"is" relationship in some very interesting ways, and eliminates some
overhead that would appear in many classes that would have otherwise had
to re-dispatch methods pertaining to their encapsulees.

Austin Hastings

unread,
Apr 23, 2004, 1:05:21 PM4/23/04
to Perl6 Language List

> -----Original Message-----
> From: Aaron Sherman [mailto:a...@ajs.com]
>
> On Fri, 2004-04-23 at 11:44, Brent 'Dax' Royal-Gordon wrote:
> > Aaron Sherman wrote:
>
> > > class c { does a for <<bar baz>>; does b for <<foo biz>>; }
>
> > Funny how similar that is to
> >
> > class c { does a handles <<bar baz>>; does b handles <<foo biz>>; }
>
> In "Relationship to Roles" A12 makes the point that delegation and roles
> are not the same thing.
>
> To tie them together with C<handles> MIGHT be wise and might not. I'll
> have to think about that and see what others post on the topic.

This seems good at first blush:

"handles" means "when I'm asked to do this, it is taken care of by this
other"

That seems like a good disambiguation marker, too:

class Trog does Tree does Dog {...}

# error: conflicting 'bark' methods

class Trog
is PersistentObject
handles «meta dispatch SERIALIZE»
does Tree
handles «bark»
does Dog
{...}

=Austin

Aaron Sherman

unread,
Apr 23, 2004, 2:28:18 PM4/23/04
to Larry Wall, Perl6 Language List
On Fri, 2004-04-23 at 14:17, Larry Wall wrote:

> : does Tree
> : handles «bark»
> : does Dog

> That works in the case of an explicitly named method, since that
> effectively makes .bark a method in the current class. It would not
> work for a wildcard delegation though, unless Dog were specifically
> marked not to handle .bark.

That's fine.

I would expect wildcard delegation not to care about method conflicts at
all, since what's being done is, by its nature, much more dynamic
anyway.

Austin Hastings

unread,
Apr 23, 2004, 2:41:51 PM4/23/04
to Perl6 Language

> -----Original Message-----
> From: Larry Wall [mailto:la...@wall.org]
>
> On Fri, Apr 23, 2004 at 01:05:21PM -0400, Austin Hastings wrote:
> : That seems like a good disambiguation marker, too:


> :
> : class Trog does Tree does Dog {...}
> :
> : # error: conflicting 'bark' methods
> :
> : class Trog
> : is PersistentObject
> : handles «meta dispatch SERIALIZE»

> : does Tree
> : handles «bark»
> : does Dog

> : {...}


>
> That works in the case of an explicitly named method, since that
> effectively makes .bark a method in the current class. It would not
> work for a wildcard delegation though, unless Dog were specifically
> marked not to handle .bark.
>

Junctions to the rescue!

class Trog


does Tree
handles «bark»
does Dog

handles none«bark»
{...}

=Austin

Larry Wall

unread,
Apr 23, 2004, 2:17:36 PM4/23/04
to Perl6 Language List
On Fri, Apr 23, 2004 at 01:05:21PM -0400, Austin Hastings wrote:
: That seems like a good disambiguation marker, too:

:
: class Trog does Tree does Dog {...}
:
: # error: conflicting 'bark' methods
:
: class Trog
: is PersistentObject
: handles «meta dispatch SERIALIZE»
: does Tree
: handles «bark»
: does Dog
: {...}

That works in the case of an explicitly named method, since that


effectively makes .bark a method in the current class. It would not
work for a wildcard delegation though, unless Dog were specifically
marked not to handle .bark.

Larry

Aaron Sherman

unread,
Apr 23, 2004, 2:55:51 PM4/23/04
to Larry Wall, Perl6 Language List
On Fri, 2004-04-23 at 14:28, Aaron Sherman wrote:

> I would expect wildcard delegation not to care about method conflicts at
> all, since what's being done is, by its nature, much more dynamic
> anyway.

I misunderstood roles when I said this... I now get why this is a
problem, sorry.

Jonathan Lang

unread,
Apr 23, 2004, 5:37:58 PM4/23/04
to Austin Hastings, Perl6
Austin Hastings wrote:

> Jonathan Lang wrote:
> > role A {has Cat $.x;}
> > role B {has Dog $.x;}
> > class Foo {does Cat; does Dog;}
> > my Foo $bar;
> > $bar.x; # Is this a Cat or a Dog?
>
> <A12>
> If, however, two roles try to introduce a method of the same name (for
> some definition of name), then the composition of the class fails, and
> the compilation of the program blows sky high--we sincerely hope. It's
> much better to catch this kind of error at compile time if you can. And
> in this case, you can.
> </A12>
>
> Since classes are autogenerating accessors based in data members, it's
> doubly reasonable to assume that the same solution will apply: conflict
> -> death.

Note that the problem extends past accessors: a role's methods can access
its attributes directly. So:

role A {has Cat $.x; method m1 {return $.x;};}
role B {has Dog $.x; method m2 {return $.x;};}


class Foo {does Cat; does Dog;}
my Foo $bar;

$bar.m1; # returns $A::x, right?
$bar.m2; # returns $B::x, right?

If the two $.x's are completely equivelent, you end up with redundant data
storage.

Then again, this may be more of a quirk than a problem...

Larry Wall

unread,
Apr 23, 2004, 5:46:56 PM4/23/04
to Perl6
On Fri, Apr 23, 2004 at 02:37:58PM -0700, Jonathan Lang wrote:
: Note that the problem extends past accessors: a role's methods can access

: its attributes directly. So:
:
: role A {has Cat $.x; method m1 {return $.x;};}
: role B {has Dog $.x; method m2 {return $.x;};}
: class Foo {does Cat; does Dog;}
: my Foo $bar;
: $bar.m1; # returns $A::x, right?
: $bar.m2; # returns $B::x, right?
:
: If the two $.x's are completely equivelent, you end up with redundant data
: storage.

Actually, it'd blow up at composition time anyway, since there's a default
readonly accessor for each $.x variable.
:
: Then again, this may be more of a quirk than a problem...

I'd like to think so. But then, I thought that about a lot of Perl 5 OO...

Larry

Dan Sugalski

unread,
Apr 23, 2004, 5:45:48 PM4/23/04
to Jonathan Lang, Austin Hastings, Perl6

I'd think, assuming roles are allowed to add attributes (and, if so,
I'd argue "what's the difference between a class and a role, then?"
but someone'd hit me), that the attribute would be role-specific. In
the above case you'd have two separate attributes.
--
Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Jonathan Lang

unread,
Apr 23, 2004, 6:34:32 PM4/23/04
to Larry Wall, Perl6
Larry Wall wrote:
> On Fri, Apr 23, 2004 at 02:37:58PM -0700, Jonathan Lang wrote:
> : Note that the problem extends past accessors: a role's methods can
> : access its attributes directly. So:
> :
> : role A {has Cat $.x; method m1 {return $.x;};}
> : role B {has Dog $.x; method m2 {return $.x;};}
> : class Foo {does Cat; does Dog;}
> : my Foo $bar;
> : $bar.m1; # returns $A::x, right?
> : $bar.m2; # returns $B::x, right?
> :
> : If the two $.x's are completely equivelent, you end up with redundant
> : data storage.
>
> Actually, it'd blow up at composition time anyway, since there's a
> default readonly accessor for each $.x variable.

OK; so add "method x {...};" to class Foo to keep it from blowing up. Foo
still has to track two scalars internally.

Actually, it's worse than that: let's add "has Elephant $.x;" to Foo
instead. Since class trumps role, does $bar.m1 now work with an Elephant,
or does it still work with a Cat?

Larry Wall

unread,
Apr 23, 2004, 9:04:12 PM4/23/04
to Perl6
On Fri, Apr 23, 2004 at 03:34:32PM -0700, Jonathan Lang wrote:
: Larry Wall wrote:
: > On Fri, Apr 23, 2004 at 02:37:58PM -0700, Jonathan Lang wrote:
: > : Note that the problem extends past accessors: a role's methods can
: > : access its attributes directly. So:
: > :
: > : role A {has Cat $.x; method m1 {return $.x;};}
: > : role B {has Dog $.x; method m2 {return $.x;};}
: > : class Foo {does Cat; does Dog;}
: > : my Foo $bar;
: > : $bar.m1; # returns $A::x, right?
: > : $bar.m2; # returns $B::x, right?
: > :
: > : If the two $.x's are completely equivelent, you end up with redundant
: > : data storage.
: >
: > Actually, it'd blow up at composition time anyway, since there's a
: > default readonly accessor for each $.x variable.
:
: OK; so add "method x {...};" to class Foo to keep it from blowing up. Foo
: still has to track two scalars internally.
:
: Actually, it's worse than that: let's add "has Elephant $.x;" to Foo
: instead. Since class trumps role, does $bar.m1 now work with an Elephant,
: or does it still work with a Cat?

I think the attributes have to be considered to belong primarily to
the role, and a role that references one of its own attributes knows
that it is doing so to the exclusion of any other similarly named
attribute in the class or in a different role. Accessing a role's
attribute from within a class or another role should really only work
as a fallback, if at all. I think people should be encouraged to use
the methods where performance is not at a premium. Most of these will
be private attributes in any event, so using the :method doesn't have
to do virtual dispatch. But private attributes also belong primarily
to the role, and only secondarily to the class or other roles. However,
the roles do implicitly trust each other by virtue of being composed
into the same class, so they can see each other's private methods.

Note that this means you can write roles that are only meaningful
when composed into a class with certain other roles or methods, and
cannot be used as mixins, since a mixin would never see the private
methods from an overridden base class. The only way to do it as a
mixin is to have a composite role containing all the other roles, and
then mix that one role in all at once. (Which is probably what you
want to do anyway for efficiency, when you know you have to mix
in multiple roles.)

Larry

0 new messages