Traits approaching mainstream Squeak

stéphane ducasse ducasse at iam.unibe.ch
Sun Aug 28 08:28:32 UTC 2005


>
>
>> Here's another general question -
>> In my opinion at the moment, and I'm curious what other people =20
>> think, in the presence of Traits, there is no excuse for =20
>> separating Behavior, ClassDescription, and Class into a hierarchy. =20=

>> The responsibilities each represents could be reused separately if =20=

>> they were Traits. So the only clearly compelling reasons to create =20=

>> classes become that you want to have instances with that shape and =20=

>> behavior. An abstract class doesn't seem to make too much sense. =20
>> So when should we use Traits to replace inheritance as a mechanism =20=

>> for sharing implementation? always? Never except when needed to =20
>> avoid duplication or the complexities of delegation?
>>
>
> Well, that's the 64k question, isn't it? If all you have is a =20
> hammer everything looks like a nail, but if you have multiple tools =20=

> you need to find out what to use when and where and how. Like, for =20
> example, why not implement traits purely using traits? We could =20
> (trivially) get rid of the abstract superclasses PureBehavior, =20
> TraitBehavior, and TraitDescription, and just have a single Object =20
> subclass: #Trait with all the behavior mixed in via traits. What =20
> would we gain? What loose?

Exact.
But we wanted not to change the interface and hierarchy. Hence the =20
extra constraints.
>
>
>>> In which places have you been avoiding inappropriate inheritance?
>>>
>> I for example think that the current inheritance of TraitBehavior =20
>> and Behavior from PureBehavior is inappropriate, and should by =20
>> replaced sharing the methods using a Trait usage. The reason for =20
>> PureBehavior existing in the demo is historical - before Traits =20
>> started functioning, that way of sharing implementation wasn't =20
>> available. That change is going to happen before integration with =20
>> mainstream, among things because it would make the Kernel =20
>> hierarchy more similar to what is there now, therefore =20
>> minimization integration costs.
>>
>
> I see. It would be interesting for me to see an actual design from =20
> first principles that ignores the restrictions we have right now =20
> (like VM dependencies) and just tries to build a comprehensive set =20
> of abstractions. Anyone up for it? It doesn't need to be =20
> implemented just being able to talk about where the =20
> responsibilities lie, what to reuse and how would be interesting.

I would love to see that! Because this is really difficult to see =20
that over the hierarchy and the rest.


>>> It seems to me that a valid alternative for avoiding inheritance =20
>>> problems is instead of duplicating the Behavior/ClassDescription/=20
>>> Class hierarchy via TraitBehavior/TraitDescription/ClassTrait =20
>>> would be to make  Trait delegate to an appropriate class =20
>>> description (e.g., a trait uses a class description for managing =20
>>> the Behavior side of things). Can you say anything about how such =20=

>>> a design would have affected the definition of traits for these =20
>>> kernel classes themself?
>>>
>> IIUC this proposal, it would require creating a class description =20
>> for every Trait. But a ClassDescription inheriting from Behavior =20
>> know too much and does too much - it is a full descriptor for =20
>> object with behavior, which a Trait isn't and doesn't need.
>>
>
> Yeah, I take this back. Delegation to an existing ClassDescription =20
> is probably not the right way to do it.
>
>
>>> BTW, the reason I'm asking these questions is to get a better =20
>>> understanding on how one uses traits effectively. Looking over =20
>>> the current uses it struck me that using a large number of fine-=20
>>> grained taits can make it actually harder to understand the =20
>>> system. At least that was my feeling when I looked over the =20
>>> current structure - none of the traits are fully defined internally
>>>
>> I'm not familiar with all of it. Lets discuss something specific, =20
>> so we can learn from it. Lets look at some specific Trait that =20
>> annoys you and see how it can be improved.
>>
>
> Well, to come back to the first part of the message let's look at =20
> the requirements for traits in ClassDescription and where we find =20
> them:
>
> For TAccessingMethodDictDescription (which I am choosing only =20
> because it's the first in the category and not too long) we have =20
> the following requirements:
>   #compiledMethodAt:ifAbsent:
>     -> TMethodDictionaryBehavior
>   #instanceSide
>     -> ClassDescription/TraitDescription
>   #organization
>     -> ClassDescription/TraitDescription
>   #isMeta
>     -> TTestingDescription
>   #updateOrganizationSelector:oldCategory:newCategory:
>     -> TTraitsCategorisingDescription
>   #whichCategoryIncludesSelector:
>     -> TBasicCategorisingDescription
>
> In this case support for a tiny trait is typically implemented =20
> using 4-5 further traits (which in turn will use other traits which =20=

> makes up for the full set of traits used in ClassDescription) and I =20=

> wonder what this does to people trying to understand the system. =20
> Understanding or changing any of these seems to become a major =20
> effort in navigating through the various traits and for some reason =20=

> that disturbs me greatly. There is a basic lack of locality of =20
> reference - something that has always disturbed me in Smalltalk but =20=

> with traits (or rather: the way it's being used right now in the =20
> class hierarchy) this may be going to extremes.

true. Me too.
>
> Do I know how to improve this? Well, I don't exactly, other than =20
> saying perhaps we should look at having few "macro traits" =20
> representing multiple responsibilities instead of "micro traits" =20
> for each individual responsibility. It may also be worthwhile to =20
> get away from the goal of "maximizing code reuse" and rather =20
> "maximize interface consistency".

Exact. We are in sync here. See my previous email.
I would favor understandability over extreme reuse.

> To me the latter is more important that the former - I don't mind a =20=

> bit of duplicated code if (for example) it makes it easier to =20
> understand the system or to reduce dependencies. But one of the =20
> most powerful features of traits is that we can extend an interface =20=

> for all classes implementing it and can do so in a concrete way - =20
> so that a new method like Collection>>gather: can be implemented in =20=

> the Collection trait (interface) and will automatically apply to =20
> all of the users (implementors) of that trait.
>
>
>> About the required browser -
>> 1. Did you use the version I announced? an earlier beta had a =20
>> critical bug, though it was in the other direction - sometimes =20
>> showed too few methods.
>>
>
> I'm not sure. I used the image that you referred to and I checked =20
> if there was a newer version on squeaksource (there wasn't) so I =20
> think the version is okay.
>
>
>> 2. Do note that requirements are a non trivial property to compute =20=

>> (including in our heads). One reason is that requirements are =20
>> often inherited. For example, Object implements #stepIn: which =20
>> self sends #step. Therefore, everything in the system that doesn't =20=

>> implement #step and does inherits #stepIn: requires #step.
>>
>
> Oh, I see. That was it - I was wondering why, for example, =20
> SmallInteger would require #step.
:)
We will discover a lot of scary methods using the new browser. It was =20=

fun how much bugs in Squeak we found just using the first browser of =20
nathanael


>>> I think it is critical that one be able to see which methods come =20=

>>> from traits and which one's don't. For example, I was curious if =20
>>> Class had any of its own methods or if all of the methods come =20
>>> from the three traits it uses[*] and also which traits are used =20
>>> by which classes (e.g., "all users of TVariablesClass").
>>>
>> Right. In the prototype this happened in two ways: non-locally =20
>> defined methods were green, and under each class that has traits, =20
>> in addition to those, there was a computed entry "-own-" that =20
>> shows only local methods.
>> Have a preference?
>>
>
> Not really. Virtual categories might work. Coloring might. Even =20
> just annotating the browser so it lists the trait in the annotation =20=

> pane might work.
>
>
>>  > In general, I think it would be helpful if some guidelines =20
>> could be
>>  > established for how to use traits in practice.
>> I think the best we can do at the moment is -
>> A. Study and discuss the existing design examples - the =20
>> collections restructure (I don't know if the code is available =20
>> somewhere) and the kernel restructure as seen in the demo.
>>
>
> I haven't seen the collection code but I'd be interested in it.

In the oopsla paper nathanael refers to
http://www.iam.unibe.ch/=A0schaerli/smalltalk/traits/=20
OOPSLACollectionRefactoring.zip
but this is not there. I asked him to let me know where is the old =20
image.

>
>> B. Start playing with these new options in our own work.
>> It's new, like Mike said, the patterns book for Traits has not yet =20=

>> been written...
>>
>
> Well, I think we have a few good things that we should try, =20
> including: What if we avoid inheritance completely? (I think that's =20=

> worth a try just to see how it feels) How would a coarse-grain set =20
> of traits "feel"?

This is a good question but too research oriented for 3.9 :)

Stef





More information about the Squeak-dev mailing list