On Sun, 24 Oct 2010, Eliot Miranda wrote:
> 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 You're right, integration is hard. It would probably be harder than the integration of Traits was. > 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? I see four benefits: - a bit better performance on current VMs - no name conflict (accessors) - accessor methods can also be reused - the ability to reuse the code of existing classes (this may cause problems) Let's see the same example as a Trait: Trait named: #TBidirectionalLink uses: #() category: 'ClassCompositionExample' TBidirectionalLink >> unlink self previous next: self next. self next previous: self previous TBidirectionalLink >> linkAfter: aBidirectionalLink self previous: aBidirectionalLink. self next: aBidirectionalLink next. aBidirectionalLink next: self. self next previous: self And the user: ECSelectorEntry subclass: #ODatedEntry uses: TBidirectionalLink instanceVariableNames: 'date next previous' classVariableNames: '' poolDictionaries: '' category: 'Ocompletion' ODatedEntry (and all other users of TBidirectionalLink) has to implement four methods (the accessors): ODatedEntry >> next ^next ODatedEntry >> next: anODatedEntry next := anODatedEntry ODatedEntry >> previous ^previous ODatedEntry >> previous: anODatedEntry previous := anODatedEntry This is only possible if ODatedEntry (or a superclass of it) doesn't implement any of these methods, otherwise the Trait can't be used. Levente > > best > Eliot > > 2010/10/24 Levente Uzonyi <[hidden email]> > >> 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 >>>>> [hidden email] >>>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project >>>>> >>>> _______________________________________________ >>>> Pharo-project mailing list >>>> [hidden email] >>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project >>>> >>> >>> >>> _______________________________________________ >>> Pharo-project mailing list >>> [hidden email] >>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project >>> >> >> _______________________________________________ >> Pharo-project mailing list >> [hidden email] >> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project >> > Pharo-project mailing list [hidden email] http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project |
Free forum by Nabble | Edit this page |