Re: RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)

2009-07-13 Thread Ovid

- Original Message 
 From: Jon Lang datawea...@gmail.com

 Right.  But as they were originally conceived, they were interfaces
 that could also handle code reuse, rather than units of code reuse
 that could also be used as interfaces.  From this perspective, it
 makes perfect sense that a role's methods can be overridden as easily
 as they are.

As originally conceived in Perl 6 or in the original traits papers?  In the 
original research, the purpose of roles was to allow the decoupling of 
responsibility and behavior (code reuse) found in inheritance-based OO systems. 
 Traits (roles) took over code reuse.

 But you make a good point: there are some (a few? most?) programmers
 who are going to want to use roles primarily for code reuse, and who
 will want it to be a little more difficult to override the code
 provided by a role (e.g., requiring the use of supersede and perhaps
 augment in order to replace the definition with a new one).

Just to give people some real data to play with (our system may not be 
representative), here's some sample source code and some imformation about our 
use of roles in the BBC.

package PIPs::ResultSource::Series;
use Moose;
extends 'PIPs::ResultSourceBase::BrandSeries';
with qw(
PIPs::ResultSource::Role::DoesParentChildRelationships
PIPs::ResultSource::Role::DoesTags
PIPs::ResultSource::Role::DoesContentObject
PIPs::ResultSource::Role::DoesInspector
PIPs::ResultSource::Role::DoesRelatedLinks
PIPs::ResultSource::Role::DoesIdentifiers
PIPs::ResultSource::Role::DoesChangeEvents
);

 
(The astute reader will not that the base class is awful, but it's been a long, 
hard slog to get this far).

Most of our classes which implement roles have similar preambles, but with 
different behaviors listed.

Other points of interest.  Only 11 of 114 classes which implement roles exclude 
any methods (none use method aliasing) and we currently have 40 roles 
implemented.  

Only three classes provide methods which override role's methods, but in the 
few cases they do, we explicitly exclude the methods from the role to make it 
clear that we need to do this.  We had more overriding of role's methods, but 
continual refactoring has pushed those into roles.

 
So we're very, very heavily on the use roles for shared behavior side.  The 
relative paucity of overridden role methods suggests to me that (for our code), 
the annoyance of having to be explicit for overridding a role's methods easily 
offset by how hard it's been to debug this issue.  That being said, the pain in 
debugging might have been a side effect of the fast transformation from a 
complex inheritance hierarchy to a roles-based system.

Cheers,
Ovid
--
Buy the book - http://www.oreilly.com/catalog/perlhks/
Tech blog- http://use.perl.org/~Ovid/journal/
Twitter  - http://twitter.com/OvidPerl
Official Perl 6 Wiki - http://www.perlfoundation.org/perl6


RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)

2009-07-12 Thread Daniel Ruoso
Em Sex, 2009-07-10 às 15:39 -0700, Jon Lang escreveu:
 The key to understanding roles is to note that roles don't implement
 methods; classes implement methods.

Er, while I see your point, Roles are not just interfaces... they are OO
components that can be plugged into other classes. They often are used
for type identity exactly because of that attribute, since you won't be
enforcing any hierarchy.

 Roles define which methods must be implemented, and suggest ways that
 they might be implemented; classes decide which implementation to use.
 Anything that breaks this paradigm is a Bad Thing.

That's not the common conception in Roles usage, specially in Moose. As
I said, Roles are not just interfaces, they are OO reuseable components.
The spec itself says:

Classes are primarily for instance management, not code reuse.
Consider using Croles when you simply want to factor out
common code.

The key issue here is Perl 6 wasn't yet used to the extent that
Moose::Roles are, and Moose people have identified that the use of Roles
as reusable components raised the issue when the class inadvertedly
overrides one of the methods that are implemented by one of the composed
roles.

I did think that this should be the expected behavior, but when the
people that is heavily using it says it took me a lot of time to
debug, it indicates that there's something wrong with the behavior.

So now I changed my mind, inheritance is about overriding behavior, so
when you implement a method in the subclass it is a natural thinking
that this should override the superclass, but when you think about it
really carefully this logic doesn't really map well to Roles
(considering roles as OO reuseable components).

That being said, I'd think the following as an interesting solution:

 role R1 {
   method foo() {...} # degenerates to interface
 }
 role R2 does R1 {
   method bar() {
 # some implementation
   }
   method baz() {
 # some implementation
   }
 }

 class Bla does R2 {
   method foo {
 # implementing here is natural, since the role only
 # declared a stub, it's even a warning not to implement it
   }
   supersede method bar  {
 # explicitly tells that I want to ignore the implementation
 # in the role. nextsame wouldn't find the role implementation.
   }
   augment method baz {
 # explicitly tells that I want to provide an additional
 # implementation besides the one in the role. nextsame would find
 # the role implementation.
   }
 }

In the above example, declaring a method without either supersede or
augment would result in a compile-time warning, while using augment
semantics by default.

dainel



Re: Reusing code: Everything but the kitchen sink

2009-07-12 Thread David Green

On 2009-Jul-10, at 4:37 pm, Jon Lang wrote:
This is one of the distinctions between role composition and class  
inheritance.  With class inheritance, the full tree of inherited  
classes is publicly accessible; with role composition, the methods  
of the combined role are the only ones that are made available to  
the class.



OK, that's actually about what I was thinking, despite the peculiar  
way I expressed it.  I meant the full names to refer to methods  
directly in the composed role, not somewhere else.  Of course, there's  
already a way to refer to methods with the same name -- using the long  
name that includes the signature.  So my example should have used  
bark(Canine: ...) and bark(Tree: ...); and whichever one actually  
gets called depends on whether the invocant does Canine or does Tree.


so Dogwood::bark ought to consider its context (am I being called to  
behave like a Canine, a Tree, or something else?) and decide what to  
do based on that.  If Dogwood::bark isn't defined, you should get an  
implementation conflict error, because the class failed in its duty  
to provide an implementation.



Yes, and Dogwood::bark could handle it by something like: if  
$self.does(Canine) {...} elsif $self.does(Tree) {...} -- but Perl  
already knows how to handle multiple dispatch based on type, so I  
shouldn't have to write it out manually.  In fact, this works with  
Rakudo: you can have both barks if you declare them as multis, and  
then it will accept them without having to declare a Dogwood::bark.   
(But of course if you try calling it, you get an Ambiguous dispatch  
to multi 'bark' error, because a $dogwood object equally satisfies  
both signatures.)


(I tried to see what would happen if you cast the $dogwood object to  
Canine or to Tree, but either Rakudo doesn't do it yet, or I got it  
wrong.)


Needing to say multi makes sense if you wanted multiple methods of  
the same name *within* a role (or class or any other namespace), but I  
don't think it should be necessary across different Roles.  Since they  
already exist in different namespaces, we know they're supposed to  
mean different things, and it's a simple fact of life that sometimes  
the same term will get used in different places for completely  
different meanings.  If you have to do the dispatching manually, I  
guess that's only a slight annoyance as long as it's possible.  (Maybe  
it's better to force the programmer to do it, not because Perl  
couldn't, but to prevent potential surprises? Hm.)




   role R { method foo() { say foo }
   role R1 does R { method bar() { say bar }
   role R2 does R { method baz() { say baz }
   class C does R1 does R1 { }

The question is whether or not Rakudo is smart enough to realize  
that R1::foo is the same as R2::foo, or if it complains that R1 and  
R2 are both trying to supply implementations for foo.  The former is  
the desired behavior.


Conversely, in this case the same name means the same thing, so it  
does seem perl ought to be able to tell that both foo's are really a  
single foo() here; since they both come from the same role (R), they  
have to mean the same thing, and C has to know that it does R.




In any case, then the question is how to know what role something  
does, which is really a question about casting and passing args rather  
than anything to do with Roles per se.  I can't tell just from  
$dogwood.bark which kind of barking is wanted; but I could have  
Dogwood::bark_like_a_dog() instead, perhaps.


However, in
   sub nighttime (Canine $rover) { $rover.bark if any(burglars()); }

I can only call .bark because all I know for sure is that I have  
something which does Canine; if I pass it a $dogwood object, I see  
three possibilities:


1) $rover in the sub is just the Dogwood object that was passed in,  
and calling $rover.bark cannot know what to do.  I also can't call  
$rover.bark_like_a_dog or anything else, because that method exists  
only for Dogwood objects, and the sub doesn't always receive  
Dogwoods.  So I'm stuck, and I don't see any way around that the way  
things are.


2) $rover does Canine and only Canine -- the Tree-half of $dogwood  
that was passed in is invisible inside the sub, and thus $rover.bark  
calls bark(Canine:) which is what we want.  (Of course, it calls  
Dogwood's bark(Canine:) when passed a Dogwood object -- it's not  
magically jumping back to the original Canine role.)  If nighttime()  
in turn calls something-else($rover), the something-else sub also gets  
only a Canine object.


3) $rover acts like a Canine, but the rest of the original $dogwood  
arg (the Tree parts) are still there; they just aren't used unless  
somehow explicitly brought out; for example, by casting $rover to a  
Tree, or by passing it to some other function that is looking for a  
Tree object.  This is how I'd like it to work, because that's the most  
flexible.


Maybe there should be hard casting and soft casting: by hard  

Re: RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)

2009-07-12 Thread David Green

On 2009-Jul-12, at 12:43 pm, Daniel Ruoso wrote:

role R1 {
  method foo() {...} # degenerates to interface
}


Just wondering: since merely declaring an interface will be common  
enough, should we be able to say simply method foo; inside a role,  
and drop the {...}?



class Bla does R2 {
  method foo {
# implementing here is natural, since the role only
# declared a stub, it's even a warning not to implement it
  }
  supersede method bar  {
# explicitly tells that I want to ignore the implementation
# in the role. nextsame wouldn't find the role implementation.
  }
  augment method baz {
# explicitly tells that I want to provide an additional
# implementation besides the one in the role. nextsame would find
# the role implementation.
  }
}


Works for me.  I thought having suggest to make it work the other  
way around sounded useful too, but perhaps you think in practice it  
wouldn't be worth it?



-David



Re: Reusing code: Everything but the kitchen sink

2009-07-12 Thread Brandon S. Allbery KF8NH

On Jul 12, 2009, at 20:15 , David Green wrote:

  sub nighttime (Canine $rover) { $rover.bark if any(burglars()); }

(...)
3) $rover acts like a Canine, but the rest of the original $dogwood  
arg (the Tree parts) are still there; they just aren't used unless  
somehow explicitly brought out; for example, by casting $rover to a  
Tree, or by passing it to some other function that is looking for a  
Tree object.  This is how I'd like it to work, because that's the  
most flexible.


If you haven't declared it as such, this strikes me as a bad thing.   
Perhaps some kind of declarative syntax that lets you declare that you  
can take a Dogwood, such that you get an added argument which is undef  
(for a non-Dogwood) or a Dogwood (or Tree?)?


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allb...@kf8nh.com
system administrator [openafs,heimdal,too many hats] allb...@ece.cmu.edu
electrical and computer engineering, carnegie mellon universityKF8NH




PGP.sig
Description: This is a digitally signed message part


Re: RFC: overriding methods declared by roles (Was: Re: Reusing code: Everything but the kitchen sink)

2009-07-12 Thread Jon Lang
Daniel Ruoso wrote:
 Jon Lang wrote:
 The key to understanding roles is to note that roles don't implement
 methods; classes implement methods.

 Er, while I see your point, Roles are not just interfaces... they are OO
 components that can be plugged into other classes. They often are used
 for type identity exactly because of that attribute, since you won't be
 enforcing any hierarchy.

Right.  But as they were originally conceived, they were interfaces
that could also handle code reuse, rather than units of code reuse
that could also be used as interfaces.  From this perspective, it
makes perfect sense that a role's methods can be overridden as easily
as they are.

But you make a good point: there are some (a few? most?) programmers
who are going to want to use roles primarily for code reuse, and who
will want it to be a little more difficult to override the code
provided by a role (e.g., requiring the use of supersede and perhaps
augment in order to replace the definition with a new one).  First and
foremost, this distinction between suggested ans mandatory
implementation is what I was trying to make a little more explicit in
my proposal: a suggested method can be overridden by the class with no
extra effort; a mandatory method requires that the class be explicit
about the override.

The next question is which of these approaches Perl 6 should use with
roles.  Currently, it's using suggested implementations; what I'm
hearing you say is that you'd rather have mandatory implementations.
IMHO, there's a time ans place for both; so I was trying to come up
with a compromise of sorts: a way of letting the programmer select the
approach that most suits his needs.

 Roles define which methods must be implemented, and suggest ways that
 they might be implemented; classes decide which implementation to use.
 Anything that breaks this paradigm is a Bad Thing.

 That's not the common conception in Roles usage, specially in Moose. As
 I said, Roles are not just interfaces, they are OO reuseable components.

FWIW, I never said that they're just interfaces.  Also, I question
whether that is or is not the common conception of role usage.  I
readily admit that it isn't so in the programming circles that you
travel in; but are you typical of the perl community in this regard?
This is not a rhetorical question; the way that we end up addressing
this issue hinges on this question: should roles provide suggested
implementations by default, or should they provide mandatory
implementations by default?  Even if Perl is rich enough to provide
for both, the decision of which way to go when no explicit decision
has been made is an important one.

 The spec itself says:

        Classes are primarily for instance management, not code reuse.
        Consider using Croles when you simply want to factor out
        common code.

Right: roles are preferable to classes when it comes to code reuse.
That doesn't necessarily mean that roles are _primarily_ intended for
code reuse.  They _might_ be; but if so, it's because they've grown
beyond their original concept.

 The key issue here is Perl 6 wasn't yet used to the extent that
 Moose::Roles are, and Moose people have identified that the use of Roles
 as reusable components raised the issue when the class inadvertedly
 overrides one of the methods that are implemented by one of the composed
 roles.

You know what?  Until Moose was mentioned in this conversation, I had
never heard of it.

 I did think that this should be the expected behavior, but when the
 people that is heavily using it says it took me a lot of time to
 debug, it indicates that there's something wrong with the behavior.

 So now I changed my mind, inheritance is about overriding behavior, so
 when you implement a method in the subclass it is a natural thinking
 that this should override the superclass, but when you think about it
 really carefully this logic doesn't really map well to Roles
 (considering roles as OO reuseable components).

That may indeed be the case.  It's entirely possible that we may want
to change things so that roles define mandated methods, and possibly
introduce interfaces as a variation of roles that define suggested
methods.  But we may instead want to keep roles as they are, and
define some other variation that works just like a role except that it
mandates its methods.

And its also possible that I'm fundamentally wrong about this, and
that we _don't_ need both approaches available for roles.

 That being said, I'd think the following as an interesting solution:

  role R1 {
   method foo() {...} # degenerates to interface
  }
  role R2 does R1 {
   method bar() {
     # some implementation
   }
   method baz() {
     # some implementation
   }
  }

  class Bla does R2 {
   method foo {
     # implementing here is natural, since the role only
     # declared a stub, it's even a warning not to implement it
   }
   supersede method bar  {
     # explicitly tells that I want to ignore the 

Re: Reusing code: Everything but the kitchen sink

2009-07-10 Thread David Green

On 2009-Jul-7, at 5:28 am, Jonathan Worthington wrote:
The spec is right in that you need to write a method in the class  
that decides what to do. This will look something like:


  method fuse() { self.Bomb::fuse() }



That makes sense for using the combined role on its own, but can we  
still handle separate roles that get mixed together?  That is, after  
defining that method so I can call $joke.fuse(), can I still call  
$joke.Bomb::fuse and $joke.Spouse::fuse as well?


I'm thinking that it's useful to be able to refer to the fully- 
qualified names for anything composed into a role or class; often  
there will be no ambiguity, so the full name won't be necessary.  If  
the names aren't unique, then you can specify them fully, and perhaps  
add an unqualified fuse() that does one or the other (or both? or  
neither??) for convenience.  That shouldn't be necessary, I think --  
it just means you would have to spell out exactly which method you  
wanted.


In the case Ovid also mentioned where two roles have a method of the  
same name because both methods really are doing the same thing, there  
ought to be a way to indicate that (though if they both come with  
implementations, you'd still have to pick one or write your own).


Of course, in a perfect world, the common method would come from its  
own role: if Foo.fuse and Bar.fuse really mean Foo.Bomb::fuse and  
Bar.Bomb::fuse, then doing Foo and Bar together should automatically  
give you a single .fuse method (again, at least as far as the  
interface is concerned).



I guess being able to create a role by dropping some bits from an  
existing role would be useful sometimes, but it seems to lose one of  
the most useful benefits of roles: as Jon Lang pointed out,  
R1 :withoutfoo bar would effectively be a new role, one that  
doesn't do R1.  But you want something to do a role in the first place  
so that it will work anywhere else there is code looking for that role.


So supposing:

   role Canine { method bark { say ruff; } };
   role Tree   { method bark { say rough } };

   class Dogwood does Canine does Tree { ... };
   my Dogwood $dw;

   sub nighttime (Canine $rover) { $rover.bark if any(burglars()); }
   sub paper (Canine $rex) { $rex.bark if newspaper(:delivered); }
   sub paper (Tree $nodes) { $nodes.bark == flatten; ... }

What happens when I call nighttime($dw)?  Obviously, it's meant to  
call $dw.Canine::bark. Since nighttime() is looking for something that  
does the Canine role, any method calls in that function can safely be  
assumed to be short for .Canine::bark (since all we know for sure is  
that any arg passed in will do Canine, and we can't know it will do  
anything else).


If I want to call paper(), then I would have to cast $dw to either one  
of the roles, e.g. paper(Tree($dw)), and that would presumably strip  
off or hide the Canine part of its nature.  It doesn't seem  
unreasonable for any non-Tree attributes to be inaccessible inside  
paper(Tree), since all it can guarantee is the arg does Tree; but on  
the other hand, I think it would be OK but would require you to use  
the fully qualified names for anything non-Tree.


If Dogwood defines its own .bark method, I can see it meaning one of  
two things: either it's yet another bark(), specifically  
$dw.Dogwood::bark(), that can be used only where we're expecting a  
Dogwood object.  (It might bear no relation to Canine::bark or  
Tree::bark, although in that case it would probably be a good idea to  
pick a different name!)  Or else, it could mean a consolidation of the  
two mixed-in .bark's, i.e. $dw.Canine::bark and $dw.Tree::bark would  
both now be implemented by plain $dw.bark, aka $dw.Dogwood::bark (all  
three full names would mean the same thing for Dogwood objects).




-David



Re: Reusing code: Everything but the kitchen sink

2009-07-10 Thread Jon Lang
The key to understanding roles is to note that roles don't implement
methods; classes implement methods.  Roles define which methods must
be implemented, and suggest ways that they might be implemented;
classes decide which implementation to use.  Anything that breaks this
paradigm is a Bad Thing.

Where things get slightly fuzzy is that there is one case where a
class is implicitly assumed to accept an implementation suggested by a
role - namely, if that implementation is the only one available.
Otherwise, the role is required to explicitly define a given method's
implementation.

David Green wrote:
 Jonathan Worthington wrote:
 The spec is right in that you need to write a method in the class that
 decides what to do. This will look something like:

  method fuse() { self.Bomb::fuse() }

 That makes sense for using the combined role on its own, but can we still
 handle separate roles that get mixed together?  That is, after defining that
 method so I can call $joke.fuse(), can I still call $joke.Bomb::fuse and
 $joke.Spouse::fuse as well?

This is one of the distinctions between role composition and class
inheritance.  With class inheritance, the full tree of inherited
classes is publicly accessible; with role composition, the methods of
the combined role are the only ones that are made available to the
class.  In effect, a combined role acts as a middle manager that looks
over the available implementations and picks one, provides its own
alternative, or defers the decision to its boss (i.e., the class or
role into which it is composed).  Either way, once the class has
chosen an implementation, that is the implementation that will be
used.

As I understand it, the reason for this has more to do with attributes
than with methods: with role composition, you want to be able to cut
away any attributes that have become extraneous to the
implementations defined in the class.  E.g.:

role R {
has $foo;
}

class C does R {
method foo() is rw { doIO() }
}

The idea here is that C has chosen to implement foo by querying an
outside source (such as a database) whenever a read request is made of
it, and by sending information to an outside source whenever a write
request is made.  It never refers to the internal state that R
defined.  As such, there's no reason for C to set aside memory to
track an internal state.  You can't do this if someone is allowed to
explicitly call R::foo from any object of class C, overriding C's
choice as to how foo should be implemented.

 I'm thinking that it's useful to be able to refer to the fully-qualified
 names for anything composed into a role or class; often there will be no
 ambiguity, so the full name won't be necessary.  If the names aren't unique,
 then you can specify them fully, and perhaps add an unqualified fuse()
 that does one or the other (or both? or neither??) for convenience.  That
 shouldn't be necessary, I think -- it just means you would have to spell out
 exactly which method you wanted.

This is class inheritance think.  In role composition think, you
should never have to worry about how the composed roles might have
done things once composition is complete; you only concern yourself
with how the class does things.

 In the case Ovid also mentioned where two roles have a method of the same
 name because both methods really are doing the same thing, there ought to be
 a way to indicate that (though if they both come with implementations, you'd
 still have to pick one or write your own).

 Of course, in a perfect world, the common method would come from its own
 role: if Foo.fuse and Bar.fuse really mean Foo.Bomb::fuse and
 Bar.Bomb::fuse, then doing Foo and Bar together should automatically give
 you a single .fuse method (again, at least as far as the interface is
 concerned).

You have a point: it would be nice if you didn't have to engage in
unnecessary conflict resolution.  Of course, this may actually be the
case already; it all depends on how the compiler decides when to
complain about conflicting methods.

role R { method foo() { say foo }
role R1 does R { method bar() { say bar }
role R2 does R { method baz() { say baz }
class C does R1 does R1 { }

The question is whether or not Rakudo is smart enough to realize that
R1::foo is the same as R2::foo, or if it complains that R1 and R2 are
both trying to supply implementations for foo.  The former is the
desired behavior.

 I guess being able to create a role by dropping some bits from an existing
 role would be useful sometimes, but it seems to lose one of the most useful
 benefits of roles: as Jon Lang pointed out, R1 :withoutfoo bar would
 effectively be a new role, one that doesn't do R1.  But you want something
 to do a role in the first place so that it will work anywhere else there is
 code looking for that role.

Obviously, someone who explicitly drops methods from a role isn't
concerned with the new role being usable wherever the original role
could 

Re: Reusing code: Everything but the kitchen sink

2009-07-10 Thread Jon Lang
The key to understanding roles is to note that roles don't implement
methods; classes implement methods.  Roles define which methods must
be implemented, and suggest ways that they might be implemented;
classes decide which implementation to use.  Anything that breaks this
paradigm is a Bad Thing.

Where things get slightly fuzzy is that there is one case where a
class is implicitly assumed to accept an implementation suggested by a
role - namely, if that implementation is the only one available.
Otherwise, the role is required to explicitly define a given method's
implementation.

David Green wrote:
 Jonathan Worthington wrote:
 The spec is right in that you need to write a method in the class that
 decides what to do. This will look something like:

  method fuse() { self.Bomb::fuse() }

 That makes sense for using the combined role on its own, but can we still
 handle separate roles that get mixed together?  That is, after defining that
 method so I can call $joke.fuse(), can I still call $joke.Bomb::fuse and
 $joke.Spouse::fuse as well?

This is one of the distinctions between role composition and class
inheritance.  With class inheritance, the full tree of inherited
classes is publicly accessible; with role composition, the methods of
the combined role are the only ones that are made available to the
class.  In effect, a combined role acts as a middle manager that looks
over the available implementations and picks one, provides its own
alternative, or defers the decision to its boss (i.e., the class or
role into which it is composed).  Either way, once the class has
chosen an implementation, that is the implementation that will be
used.

As I understand it, the reason for this has more to do with attributes
than with methods: with role composition, you want to be able to cut
away any attributes that have become extraneous to the
implementations defined in the class.  E.g.:

role R {
has $foo;
}

class C does R {
method foo() is rw { doIO() }
}

The idea here is that C has chosen to implement foo by querying an
outside source (such as a database) whenever a read request is made of
it, and by sending information to an outside source whenever a write
request is made.  It never refers to the internal state that R
defined.  As such, there's no reason for C to set aside memory to
track an internal state.  You can't do this if someone is allowed to
explicitly call R::foo from any object of class C, overriding C's
choice as to how foo should be implemented.

 I'm thinking that it's useful to be able to refer to the fully-qualified
 names for anything composed into a role or class; often there will be no
 ambiguity, so the full name won't be necessary.  If the names aren't unique,
 then you can specify them fully, and perhaps add an unqualified fuse()
 that does one or the other (or both? or neither??) for convenience.  That
 shouldn't be necessary, I think -- it just means you would have to spell out
 exactly which method you wanted.

This is class inheritance think.  In role composition think, you
should never have to worry about how the composed roles might have
done things once composition is complete; you only concern yourself
with how the class does things.

 In the case Ovid also mentioned where two roles have a method of the same
 name because both methods really are doing the same thing, there ought to be
 a way to indicate that (though if they both come with implementations, you'd
 still have to pick one or write your own).

 Of course, in a perfect world, the common method would come from its own
 role: if Foo.fuse and Bar.fuse really mean Foo.Bomb::fuse and
 Bar.Bomb::fuse, then doing Foo and Bar together should automatically give
 you a single .fuse method (again, at least as far as the interface is
 concerned).

You have a point: it would be nice if you didn't have to engage in
unnecessary conflict resolution.  Of course, this may actually be the
case already; it all depends on how the compiler decides when to
complain about conflicting methods.

role R { method foo() { say foo }
role R1 does R { method bar() { say bar }
role R2 does R { method baz() { say baz }
class C does R1 does R1 { }

The question is whether or not Rakudo is smart enough to realize that
R1::foo is the same as R2::foo, or if it complains that R1 and R2 are
both trying to supply implementations for foo.  The former is the
desired behavior.

 I guess being able to create a role by dropping some bits from an existing
 role would be useful sometimes, but it seems to lose one of the most useful
 benefits of roles: as Jon Lang pointed out, R1 :withoutfoo bar would
 effectively be a new role, one that doesn't do R1.  But you want something
 to do a role in the first place so that it will work anywhere else there is
 code looking for that role.

Obviously, someone who explicitly drops methods from a role isn't
concerned with the new role being usable wherever the original role
could 

Reusing code: Everything but the kitchen sink

2009-07-08 Thread Jon Lang
Jonathan Worthington wrote in YAPC::EU and Perl 6 Roles:
 More fitting to me would be an adverb to the does trait modifier...

 class C does R1 :withoutfoo bar does R2 :withoutbaz { ... }

 The thing is that in this case, does the class actually do R1 and R2? If you
 are going to derive an anonymous role with the methods missing, then answer
 is no. That is, C ~~ R1 would be false.  So I think it'd need to act as a
 modifier to the action of composition, rather than a modification to the
 thing that we're composing.

Moving the adverb from the role to the trait modifier would still
violate the notion that C ~~ R1; so it doesn't actually gain us
anything.  Instead, consider the following possibility: R1
:withoutfoo bar is a separate but related role from R1.  The
implicit relationship between them is that R1 ~~ R1 :withoutfoo bar.
 So C ~~ R1 would be false; but C ~~ R1 :withoutfoo bar would be
true.

 I wonder if we'd want to mandate that a method of the name must come from
 _somewhere_ otherwise it's an error. At least then you get a promise that a
 method of that name exists...which is about all that it does this role
 tells you as an interface contract anyway.

Right.  Another way to handle this without establishing reverse-does
relationships that I describe above would be to say that the adverb
doesn't actually remove the method in question; it just suppresses its
implementation.  That is, given:

role R1 {
method foo() { say foo }
}

class C does :blockingfoo R1 { ... }

this would compose R1 into C, but would discard the implementation of
R1::foo while doing so.

In the spirit of TIMTOWTDI, both approaches could be available:

R1 :withoutfoo acts as an anonymous role that R1 implicitly does,
and which is set up almost exactly like R1 except that it doesn't have
method foo.  This could have other uses besides role composition, such
as expanding a web of roles from the specific to the general.

C does :blockingfoo R1 composes R1 into C, but discards foo's
implementation while doing so.

 Alternatively, I could see a version of this exclusionary policy being
 done through method delegation, by means of the whatever splat -
 something like:

  class C {
      has A $a handles * - (foo, bar);
      has B $b handles * - baz;
  }

 The RHS of the handles is something we smart-match the method name against
 (unless it's one of the special syntactic cases). And thus if you care about
 performance you probably don't want to be falling back to handles to do your
 role composition, since it's kind of the last resort after we've walked
 the MRO and found nothing.

You're right, but for a different reason.  Perl 6 has three techniques
for code reuse, which I refer to as the be, do, have triad:

Class inheritance (to be): 'is C;'
Role composition (to do): 'does R;'
Attribute delegation (to have): 'has A $a handles foo;'

Just on a conceptual level, you don't want to fall back on attribute
delegation in order to emulate role composition.  Still, there are
uses for delegating to all or most of an attribute's methods.

 Anyway, you'd put something on the RHS maybe
 like:

 has A $a handles none(foo bar)

 But I'm not sure that will fall through to B for anything that A doesn't
 define other than those two. You'd perhaps just get a dispatch error if you
 said A handles everything but those and it didn't. So it'd probably look
 more like...

 has A $.a handles all(any(A.^methods.name), none(foo bar));

 Which you almost certainly don't want to be writing. ;-)

Right; which is why I was looking for a more abbreviated form.  If we
go with the idea that we're using a Set on the RHS, then '*' could be
shorthand for 'Set($a.^methods)', and 'Set::infix:-' could be the
Set Difference operator, with the item, list, or set on the RHS being
excluded from the LHS.  So:

$a handles * - foo bar

would be short for something like:

$a handles Set($a.^methods) - Set(foo, bar)

This use of the Whatever splat is similar to its use in a list index,
where '*' behaves as if it were the list's element count.

--

Looking this over, I note that the only code reuse mechanism for which
we haven't looked at the everything except... concept is class
inheritance.  OTOH, I think that the blocking tool that works for role
composition could be adapted for use with class inheritence as well:

Class C is :blockingfoo bar C1 is :blockingbaz C2 { ... }

That is, if you were to search the class heierarchy for foo, it would
skip the C1 branch in its search.  This would have to be treated with
care, because it would mean that C doesn't inherit everything from C1.
 This _would_ break the anything you can do I can do, too nature of
class inheritence; but I'm not sure how big of a crime that is.  Perl
generally discourages the use of class hierarchies, and it certainly
isn't the preferred means of type-checking.  And maybe you could get
around this by having the isa predicate return a more involved
response than