Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The False Cognate problem and what Roles are still missing

1 view
Skip to first unread message

Aristotle Pagaltzis

unread,
Aug 20, 2008, 6:16:12 PM8/20/08
to Perl 6 Language
Hi $Larry et al,

I brought this up as a question at YAPC::EU and found to my
surprise that no one seems to have thought of it yet. This is
the mail I said I’d write. (And apologies, Larry. :-) )

Consider the classic example of roles named Dog and Tree which
both have a `bark` method. Then there is a class that for some
inexplicable reason, assumes both roles. Maybe it is called
Mutant. This is standard fare so far: the class resolves the
conflict by renaming Dog’s `bark` to `yap` and all is well.

But now consider that Dog has a method `on_sound_heard` that
calls `bark`.

You clearly don’t want that to suddenly call Tree’s `bark`.

Unless, of course, you actually do.

It therefore seems necessary to me to specify dispatch such that
method calls in the Dog role invoke the original Dog role methods
where such methods exist. There also needs to be a way for a
class that assumes a role to explicitly declare that it wants
to override that decision. Thus, by default, when you say that
Mutant does both Dog and Tree, Dog’s methods do not silently
mutate their semantics. You can cause them to do so, but you
should have to ask for that.

I am, as I mentioned initially, surprised that no one seems to
have considered this issue, because I always thought this is what
avoiding the False Cognate problem of mixins, as chromatic likes
to call it, ultimately implies at the deepest level: that roles
provide scope for their innards that preserves their identity and
integrity (unless, of course, you explicitly stick your hands in),
kind of like the safety that hygienic macros provide.

Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>

Jon Lang

unread,
Aug 20, 2008, 10:40:31 PM8/20/08
to Perl 6 Language

My thoughts:

Much of the difficulty comes from the fact that Mutant [i]doesn't[/i]
rename Dog::bark; it overrides it. That is, a conflict exists between
Dog::bark and Tree::bark, so a class or role that composes both
effectively gets one that automatically fails. You then create an
explicit Mutant::bark method that overrides the conflicted one; in its
body, you call the Tree::bark method (or the Dog::bark method, or both
in sequence, or neither, or...) As such, there's no obvious link
between Mutant::bark and Tree::bark. Likewise, you don't rename
Dog::bark; you create a new Mutant::yap that calls Dog::bark.

One thing that might help would be a trait for methods that tells us
where it came from - that is, which - if any - of the composed methods
it calls. For instance:

role Mutant does Dog does Tree {
method bark() was Tree::bark;
method yap() was Dog::bark;
}

As I envision it, "was" sets things up so that you can query, e.g.,
Mutant::yap and find out that it's intended as a replacement for
Dog::bark. Or you could ask the Mutant role for the method that
replaces Dog::bark, and it would return Mutant::yap.

It also provides a default code block that does nothing more than to
call Dog::bark; unless you override this with your own code block, the
result is that Mutant::yap behaves exactly like Dog::bark.

By default, this is what other methods composed in from Dog do: they
ask Mutant what Dog::bark is called these days, and then call that
method. All that's left is to decide how to tell them to ask about
Tree::bark instead, if that's what you want them to do.

--
Jonathan "Dataweaver" Lang

Chromatic

unread,
Aug 21, 2008, 5:05:30 PM8/21/08
to perl6-l...@perl.org, Aristotle Pagaltzis
On Wednesday 20 August 2008 15:16:12 Aristotle Pagaltzis wrote:

> It therefore seems necessary to me to specify dispatch such that
> method calls in the Dog role invoke the original Dog role methods
> where such methods exist. There also needs to be a way for a
> class that assumes a role to explicitly declare that it wants
> to override that decision. Thus, by default, when you say that
> Mutant does both Dog and Tree, Dog’s methods do not silently
> mutate their semantics. You can cause them to do so, but you
> should have to ask for that.

How much of this does compile-time role method collision detection provide?
If Dog and Tree both provide the bark method, the performing entity must
disambiguate them.

(I thought we had some syntax for "When invoked as a Dog, do this and when
invoked as a Tree, do that" but I'm far too lazy to look that up at this
moment.)

-- c

0 new messages