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 :without<foo 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).


Reply via email to