Navigating traits in 3.9

Andreas Raab andreas.raab at gmx.de
Sun Oct 22 20:50:48 UTC 2006


Hi Adrian -

> Anyway, lets go through your problems step by step:

Thanks, it is very much appreciated. BTW, I'm slowly getting a feel for 
what exactly seems to be so hard about traits and their relationships 
and I'll talk a little more about it below.

>> Browsing the senders of the former netted me 9 places to look at 
>> among which were four implementors of #addSelector:withMethod:. And so 
>> began the tale of the traits...
> 
> If you had used the OmniBrowser tools as I suggested in the other mail 
> you would see that among the 4 implementers of #addSelector:withMethod: 
> there are 3 that do not implement the method locally but obtain it from 
> a trait. This leaves us with exactly _one_ case to look at: 
> TCompilingBehavior.

That's strictly speaking correct, but lacks one critical bit of 
information namely what the relationships between the other listed 
entities are and whether they are relevant for the user. If this were in 
a (single inheritance) class tree, I would want to look at the hierarchy 
to figure out which of these places may turn out to be relevant. And 
this information (like Behavior using TPureBehavior using 
TCompilingBehavior) turned out to be quite important later on. With 
"just" looking at TCompilingBehvavior it's like looking at a class 
implementing some message without knowing whether that's  a superclass 
or a subclass of the place you're interested in (because if I understand 
it correctly, a "user" of TCompilingDescription could just implement 
that method and would show up just like TCompilingDescription). As a 
user, right now it feels as if you've found "two interesting places" 
without being able to correlate them.

>> Trying to find the users of TAccessingMethodDictDescription leaves us 
>> fishing through menus with no success. "class refs" does nothing, so 
>> does Cmd-Shift-N
> 
> Of course not. There aren't any references to traits in methods -- just 
> as there are usually no references to abstract classes.
> Again, the problem is a missing UI. To get the users of a trait, do 
> "TAccessingMethodDictDescription users"

I think this needs fixing. Key relationships have always have menu 
entries in the browsers - we don't ask people to print "FooClass 
superclass" any more than we ask them to print "FooClass subclasses" to 
figure out its dependencies. A simple fix could be to change the wording 
from "class refs" to "users of ..." since that works for both classes 
and traits and can do the right thing dynamically based on the selection.

Same goes for "show hierarchy" where we really want to print a combined 
tree for subclasses and traits to make clear what the relationships are.

[... snip ...]
> For example, between Behavior and TraitBehavior there is one trait named 
> TPureBehavior (in this case it saves us from duplicating about 100 
> methods). The same way the classes further down the hierarchy share 
> traits. So, that's pretty straightforward, isn't it?

Well, as far as that goes, yes. But I'm still confused. Let's see: After 
visualizing (e.g., writing down) who depends on what, what I gathered so 
far is that TCompilingDescription is used by TPureBehavior which is used 
by Behavior and TraitBehavior. And TCompilingDescription itself 
implements both #addSelector:withMethod: as well as 
#addSelector:withMethod:notifying:.

Simply put my question is: How does TAccessingMethodDictDescription come 
into play here? Why does it implement #addSelector:withMethod:notifying: 
given that it is not a user of TCompilingDescription and therefore not 
responsible for managing adding/removing selectors (which is all handled 
in TCompilingDescription)? If there is a relationship between the two 
and that method, were is that relationship stated?

A "second order" question is: Why is it even possible to use traits in 
such a conflicting way? Shouldn't there be some way of ensuring that a 
protocol that is defined by a trait in a superclass doesn't get 
redefined nilly-willy by a trait in a subclass?

Along the same lines, are you aware that TraitDescription uses 
TTransformationCompatibility and ClassTrait (being a subclass of 
TraitDescription) uses it, too? Is there a point which I'm missing to 
that duplication? (I doubt it, in which case it's an interesting data 
point about the complexities of understanding relationships with traits 
and classes since I'd assume that at least a dozen people have looked at 
it and missed that duplication)

> What's probably adding a lot of confusion is that those traits are again 
> decomposed into sub-traits. This wasn't done to avoid code duplication 
> but rather as an attempt to factor out methods into logical groups. It 
> seems that this just adds unnecessary confusion because without good 
> tools the decomposition is not obvious.

Yes, that's definitely part of it. The main problem as I see it, is that 
you're creating two tree structures, one for the traits using each 
other, and one for the class hierarchy, and then you "mix in" selected 
nodes of the traits tree into the class tree. And since there are no 
requirements about which traits you can mix into which classes it is 
perfectly possible to create "logical cycles" where one trait uses 
another but in the class hierarchy it's exactly the other way around (a 
superclass using the "sub-trait" and the subclass using the 
"super-trait"). That's an extreme example but points out the fundamental 
problem of mapping these tree structures into each other.

Interestingly, this cannot happen in most MI systems I'm aware about. 
Usually the rules of what can be inherited from where are pretty 
strictly aligned with the hierarchies (if the ability to inherit from 
the same tree exists at all).

> Now, if _this_ does not help you to understand how this all works...

It does. OTOH, it also makes me understand a lot better what I dislike 
about traits - it seems to boil down to the same old MI arguments (which 
are basically: hard to understand and difficult to use "right" because 
of the complexity of the resulting structures).

Cheers,
   - Andreas



More information about the Squeak-dev mailing list