TSa wrote:
> Jon Lang wrote:
>> I have some more thoughts on this; but I'm on a time crunch at the
>> moment, and would really like to get some feedback on the above before
>> proceeding further: have I missed anything in my reasoning?
> I fully understand what you mean, I hope. But note that all instances
> of the class that does the two roles do both roles. So the object at
> hand can't select the dispatch target. So it has to come from the
> *environment* of the call. I consider this as very problematic because
> essentially you have to import that into the object so that it can be
> carried for a while---this is what you call wearing a role hat. We
> should keep the class dispatch as simple as possible and not mix in
> the environment of the call into the meaning of an object!

Usually, I'd agree with you - and even here, I'd say that if you can
somehow resolve the dilemma without reference to the environment, that
would be preferable.  However, the only options that appear to be
available without it are the two that Ovid outlined: rewrite one of
the roles, or omit one of them.  Both of these options become
impractical once you account for the likes of CPAN:

* Rewriting one of the roles may not be possible if the programmer
doesn't own either of the offending roles; and even if it is possible,
it likely involves a massive search-and-replace operation that isn't
easily automated.

* Omitting one of the roles is reasonable as long as you can guarantee
that the overall concepts that the roles represent shouldn't be mixed
(as is arguably the case for the traditional Dogwood example); but
it's less than satisfactory when the only reason they can't be mixed
is that each role's author made an unfortunate naming choice for one
of the methods.

My proposal isn't perfect, either: if an established routine fails to
place the appropriate hat on the schizophrenic object, the
environment-based disambiguation won't DWIM and the programmer will be
forced to explicitly resolve the conflict before passing the object
into that routine.  Still, I don't get the same sense of it being a
potential show-stopper the way that I get from the alternatives.

But, as always, the devil's in the details.  Perhaps someone _can_
provide a means of rewriting one of the roles in a way that won't
break anything (the interface, the compiler's back, or the
programmer's mind).  And it may turn out that my proposal is
unworkable once we start looking into the details of how it would be

You mentioned that my approach involves importing a bit of the
environment into the object for a while.  How might this be done in a
way that won't wreak havoc?  One possibility would be to hide it away
as a trait of WHAT, and then look for that trait when it comes time to
disambiguate the schizo invocants:

    sub party(Drinking $x) { # $x.WHAT:role = Drinking
        ... $x.go_to_bar; ... # same as $x.go_to_bar:(Drinking:)

    sub compete(Gymnast $x) { # $x.WHAT:role = Gymnast
        ... $x.go_to_bar; ... # same as $x.go_to_bar:(Gymnast:)

    sub joke($x) { $x.WHAT:role is not set
        ... $x.go_to_bar; ... # can't be resolved without more information

    given Gymnast $x { # $x.WHAT:role = Gymnast
        ... joke($x); ... # the joke is about a Gymnast's bar.

Likewise, a method that originated in Drinking (such as .buy_beer)
would set self.WHAT:role to Drinking, thus resulting in any call to
.go_to_bar getting the right method from the class. (Thanks for the
example, Jonathan; I hadn't thought of that rather obvious case.)  If
DrunkGymnast replaces .buy_beer or adds a new method that calls
.go_to_bar, it won't automatically have knowledge of which hat it
should be wearing; but that's OK, because it's expected to know about
both hats, and can explicitly don the right one before (or when)
calling the conflicted method.  It's only those environments that
can't be expected to know about the dual possibilities that concern

What other problems might arise, and how might they be solved?

Jonathan "Dataweaver" Lang

Reply via email to