[Pharo-project] Smells looking at collections

Eliot Miranda eliot.miranda at gmail.com
Sun Oct 24 22:06:43 EDT 2010


Hi Levente,

    in my experience playing with the Dan and Alan Borning's multiple
inheritance implementation getting things to work was one thing, reasonably
straighforward, but getting tool support right (file-out format so that
things filed back in correctly, etc) was another, an dth ebulk of the work.
Looking at your proposal below I see no problem getting it to work but see
lots of problems integrating it, e.g. with Monticello, etc.  Traits is
already integrated with Monticello, supported with tests, etc.  As such it
is a much less risky or effortful proposition than a new scheme.  So with
that in mind are there important functional benefits of your scheme's direct
state access as compared with traits that use accessors to access state that
each user of a trait must implement?  i.e. what are the key benefits you see
in direct inst var access?

best
Eliot

2010/10/24 Levente Uzonyi <leves at elte.hu>

> On Sun, 24 Oct 2010, Stéphane Ducasse wrote:
>
>
>>>>
>>>>>  2) well, this is difficult to get the money for the butter and the
>>>>>> butter - we are trying.
>>>>>>
>>>>>
>>>>> If you can compose classes the way you can add a trait to a class now
>>>>> with class and optional method level instance+class variable mapping, then
>>>>> you're done. It would be a lot simpler to use it _and_ it would also be a
>>>>> lot easier to implement it. Especially the tools part.
>>>>>
>>>>
>>>> I'm interested to hear more about that.
>>>>
>>>
>> so can you explain what you meant because I did not understand it.
>>
>
> Okay, here is an example of my class composition idea. It works like
> Traits, but it supports state and there's no distinction between a trait and
> a class. Let's say I have a class named BidirectionalLink which can be used
> as a link in a linked list (with a head element). This will be used as a
> stateful trait. It's definition is like this:
>
> Object subclass: #BidirectionalLink
>        instanceVariableNames: 'next previous'
>        classVariableNames: ''
>        poolDictionaries: ''
>        category: 'ClassCompositionExample'
>
> It has a few methods:
>
> BidirectionalLink >> next
>        ^next
>
> BidirectionalLink >> next: aBidirectionalLink
>        next := aBidirectionalLink
>
> BidirectionalLink >> previous
>        ^previous
>
> BidirectionalLink >> previous: aBidirectionalLink
>        previous := aBidirectionalLink
>
> BidirectionalLink >> unlink
>        previous next: next.
>        next previous: previous
>
> BidirectionalLink >> linkAfter: aBidirectionalLink
>        previous := aBidirectionalLink.
>        next := aBidirectionalLink next.
>        aBidirectionalLink next: self.
>        next previous: self
>
> I have an existing class, let's call it ODatedEntry :). It has the
> following definition:
>
> ECSelectorEntry subclass: #ODatedEntry
>        instanceVariableNames: 'date'
>        classVariableNames: ''
>        poolDictionaries: ''
>        category: 'Ocompletion'
>
> As you can see, it inherits some state and behavior from ECSelectorEntry.
> My goal is to use the instances of this class in a linked list. So these
> objects should implement the same protocol with the same behavior as
> BidirectionalLink. I can't make it a subclass of BidirectionalLink, because
> I also need the behavior and state from ECSelectorEntry and we don't have
> multiple inheritance. So I'll compose the two classes. First I add the
> necessary instance variables to the class. Let's call them nextEntry and
> previousEntry:
>
> ECSelectorEntry subclass: #ODatedEntry
>        instanceVariableNames: 'date nextEntry previousEntry'
>        classVariableNames: ''
>        poolDictionaries: ''
>        category: 'Ocompletion'
>
> Then do the composition:
>
> ECSelectorEntry subclass: #ODatedEntry
>        uses: BidirectionalLink
>        instanceVariableNames: 'date nextEntry previousEntry'
>        classVariableNames: ''
>        poolDictionaries: ''
>        category: 'Ocompletion'
>
> Now this doesn't work, because ODatedEntry doesn't have instance variables
> named next and previous, but the methods of BidirectionalLink would like to
> use them. Of course I could have used those names in the previous step and
> (with a working implementation) this would just work out of the box. But the
> example is about the instance variable mapping. Let's say ~ is the
> composition operator which defines variable mapping for a class or a method.
> Then I can write the following:
>
> ECSelectorEntry subclass: #ODatedEntry
>        uses: BidirectionalLink ~ { #nextEntry -> #next. #previousEntry ->
> #previous }
>        instanceVariableNames: 'date nextEntry previousEntry'
>        classVariableNames: ''
>        poolDictionaries: ''
>        category: 'Ocompletion'
>
> This means: take all methods from BidirectionalLink, but replace the
> variable named next with nextEntry and previous with previousEntry.
> So now ODatedEntry understands #next, #next:, #previous, #unlink, etc.
>
> This is the basic concept. There are some open questions, like:
> - what happens when a composed method (or a method sent by a composed
> method, etc) has a super send?
> - will the class also get the methods of the superclasses of the "trait"?
> - how does it work on the class side?
> - what about class variables?
> - what if I don't want to use all methods, just a few?
>
>
>>
>>  Tell us more. The problem we faced was
>>>>        - offset access = you cannot reuse bytecode of a trait because
>>>> the order of the offset can be different in each trait users
>>>>
>>>
>>> If you mean that a CompiledMethod of a trait cannot be added to the
>>> class' method dictionary, than that's not an issue. The current Trait
>>> implementation was changed, because shared CompiledMethods caused other
>>> problems.
>>>
>>
>> no this is not what I meant
>>
>>  If you mean that the same bytecodes can't be used, than that's neither a
>>> problem, because you can and should be compile the method again. Sharing
>>> trailer bytes may cause problems.
>>> So adding a method from a trait to a class is simply recompiling it in
>>> the class' context.
>>>
>>
>> this is what we wanted to avoid.
>> Also because you may have to recompile all the other methods of the class
>> hierarchy because if a trait add an instance
>> variable then you should recompile the subclasses when a trait get added
>> with a state in the superclass.
>>
>
> My idea is that traits don't add instance variables. The user of the trait
> maps the trait's variables to their own by name. So if a trait gets
> a new variable, then only the trait and subclasses have to be recompiled.
> The recompilation is postponed until a method of the trait which uses the
> new instance variable is added to a class.
>
>
>>  Instance variables should be used by name during compilation. If there's
>>> a name collision then use the instance variable map I mentioned above.
>>>
>>
>> what is that the instance variable map?
>> take the time to write an example
>>
>
> See above.
>
>
> Levente
>
>
>>         - initialization of instances variables at the trait level and the
>>>> composition at the class levele
>>>>
>>>
>>> You can always rename a trait's method in your class. So if the trait has
>>> an #initialize method, then simply rename it to #initializeFooBar and send
>>> it from the class' #initialize method.
>>>
>>
>> Yes this is what the javascript implementation does but this is not that
>> nice but may be there is no better solution.
>>
>> So indeed we could think about adding state.
>>
>>
>>
>>
>>>
>>> Levente
>>>
>>>
>>>>
>>>>>  3) again if nobody does anything and we just all cry on ourselves then
>>>>>> nothing will happen.
>>>>>>
>>>>>
>>>>> Tools are a must. No tools - no users.
>>>>>
>>>>
>>>> Exact.
>>>>
>>>>  So for now identifying traits and learning is the way. Then we can
>>>>>> refactor, redesign
>>>>>>
>>>>>
>>>>> Well, Traits are in Squeak since 2006, IIRC they were available a few
>>>>> years earlier. So in the last X (at least 4) years the only good candidate
>>>>> to become a Trait was Magnitude.
>>>>>
>>>>
>>>> Come on.
>>>> I will not answer to such statement because I'm positive thinking.
>>>>
>>>> Stef
>>>> _______________________________________________
>>>> Pharo-project mailing list
>>>> Pharo-project at lists.gforge.inria.fr
>>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>>>>
>>> _______________________________________________
>>> Pharo-project mailing list
>>> Pharo-project at lists.gforge.inria.fr
>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>>>
>>
>>
>> _______________________________________________
>> Pharo-project mailing list
>> Pharo-project at lists.gforge.inria.fr
>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>>
>
> _______________________________________________
> Pharo-project mailing list
> Pharo-project at lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.pharo.org/pipermail/pharo-dev_lists.pharo.org/attachments/20101024/3c8961fb/attachment-0001.html>


More information about the Pharo-dev mailing list