On 2009-Oct-14, at 8:52 am, Ovid wrote:
--- On Wed, 14/10/09, Jon Lang <datawea...@gmail.com> wrote:
The initial possibility that springs to mind would be to use
longnames to disambiguate between the two options - specifically,
by means of the invocant:
...or something to that effect. You'd still have a disambiguation
issue, in that you'd somehow need to specify which "hat" an object
of class C is wearing when you try to call the method.
Good, that's what I was looking for the last time this came up. (http://www.nntp.perl.org/group/perl.perl6.language/2009/07/msg32164.html
)
Except that if a consumer of C needs foo(), they have to fully
qualify the call to foo(). That violates encapsulation.
I don't see that as an encapsulation problem. A leaky encapsulation
means we have to know how something works, but when I have to
distinguish between $dogwood.Dog::bark and $dogwood.Tree::bark, I'm
distinguishing between two wholly unrelated actions (that they happen
to have some of the same letters in their names is completely
coincidental). So I have to know *what* a Dogwood object does; but I
still don't have to know how it does it.
Or to look at it the other way around: Since we refer to things by
name, those names have to be unique everywhere; so let's start out
with long, "fully-qualified" names everywhere: $dog.Dog::bark(),
$tree.Tree::bark(), $i.Int::succ, etc. Now everything's fine --
except that our fingers are getting tired from all that typing. We
want to use shortcuts to say things like $dog.bark, because there's
only one place that $dog can legitimately find a bark() method, and
that's in the Dog class, so both we and Perl can easily figure out
what is meant.
On the other hand, $dogwood.Dog::bark cannot be simplified by leaving
out the "Dog::" because then it would be ambiguous. But if we look at
it as starting with full names everywhere, and seeing what we can
leave out (rather that starting with short names and having to add
stuff in), I think it's not surprising.
In other cases, there may be no way to implicitly disambiguate. In
those cases, there would need to be an explicit way to decide which
hat the object is wearing.
I really don't think that deferring the decision works. The
"freezing" technique described in the paper allows the consumer, C,
to statically bind the method foo() in the methods in the
appropriate role which call it.
The problem with "freezing" some methods into private ones is that
those methods weren't meant to be private; if my role provides a .bark
method, I need to be able to call it.
Dynamic binding defers the decision which causes implementation
details to leak to consumers of C. This means that if you change
your roles, your consumers will potentially need to be rewritten.
But if you merely change the implementation of how bark() works
(either one), nothing needs to be rewritten. If you want to change
from Tree::bark-ing to Dog::bark-ing, then you *should* be rewriting
code, because you're completely changing what is going on, no less
than if you changed from bark()ing to fetch()ing.
-David