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).
-David