On 2009-Jul-8, at 1:49 pm, Ovid wrote:
That being said, roles also have two competing uses (though they
don't conflict as badly). As units of behavior, they provide the
functionality your code needs. However, they can also serve as an
interface.
Maybe there are Interfaces, which are, well, just interfaces, and
there are Roles, which are Interfaces plus a partial or full
implementation. Like roles and classes, roles and interfaces could be
transparently interchanged when suitable. Add some bodies to an
Interface and you've got a Role; cast a Role to an Interface and you
strip out everything but the declarations.
Behavioral: if you are primarily relying on roles to provide
behavior (as we do at the BBC), then silently discarding the role's
behavior by providing a method of the same name in your class can
lead to very confusing bugs. I've lost a lot of time debugging this
behavior.
role Stuff
{
suggest method foo { ... }
method bar { ... }
}
class Thing does Stuff
{
method foo { ... }
supersede method bar { ... }
}
Since foo() is only suggested by this role, you can easily override
it; whereas bar() needs to be explicitly superseded. (Or maybe it
should be "method foo :suggested"....)
The idea being that certain methods are expected to work by accepting
what's provided in the role most of the time, so you should rarely
have to supersede them; or they're merely suggestions, and therefore
you are expected to role^H^H roll your own most of the time. (And if
you find yourself getting annoyed that you have to type "supersede" so
much, that's probably a good clue that something went wrong somewhere
in the design.)
Either that, or just have suitable warnings that can be toggled on or
off depending on what sort of policies you need. That was actually my
first thought, and I think we should have adjustable warnings for
everything anyway, but the more I look at the above example, the more
it's growing on me.
-David