From: Jörg W Mittag on 21 Jun 2010 15:31 Eric MSP Veith wrote: > Modules are used for mixins. Is it possible -- and does it make sense at all > - -- to mixin a class into another class? I guess not? Actually, to add a bit to Brian's answer: it *is* possible and makes perfect sense. It's just not allowed in Ruby, but it *is* allowed in other languages. jwm
From: Gary Wright on 21 Jun 2010 17:52 On Jun 21, 2010, at 3:35 PM, Jörg W Mittag wrote: > Eric MSP Veith wrote: >> Modules are used for mixins. Is it possible -- and does it make sense at all >> - -- to mixin a class into another class? I guess not? > > Actually, to add a bit to Brian's answer: it *is* possible and makes > perfect sense. It's just not allowed in Ruby, but it *is* allowed in > other languages. Allowing classes to mixin other classes would change the class hierarchy from a tree to a directed acyclic graph. As soon as you do that you have to figure out how to manage the method lookup process along multiple paths. I don't think there is any sort of consensus on how to do that (i.e. different languages take different approaches) and so I'm not sure 'makes perfect sense' is an accurate characterization of the solution space for that problem. Gary Wright
From: Jörg W Mittag on 22 Jun 2010 22:08 Gary Wright wrote: > On Jun 21, 2010, at 3:35 PM, Jörg W Mittag wrote: >> Eric MSP Veith wrote: >>> Modules are used for mixins. Is it possible -- and does it make sense at all >>> - -- to mixin a class into another class? I guess not? >> Actually, to add a bit to Brian's answer: it *is* possible and makes >> perfect sense. It's just not allowed in Ruby, but it *is* allowed in >> other languages. > Allowing classes to mixin other classes would change the class > hierarchy from a tree to a directed acyclic graph. As soon as you > do that you have to figure out how to manage the method lookup > process along multiple paths. I don't think there is any sort of > consensus on how to do that (i.e. different languages take > different approaches) and so I'm not sure 'makes perfect sense' is > an accurate characterization of the solution space for that > problem. You can take the algorithm Ruby uses for mixins and simply substitute classes for modules and it would work exactly the way it does today, including the linearization property. The way mixins work in Ruby is (roughly) as follows (assume that we want to mix ⟦M⟧ into a class ⟦C⟧, ignore for a moment the case of mixing a mixin into another mixin): 1. create an anonymous class ⟦I⟧ 2. set ⟦I⟧'s method table pointer to ⟦M⟧'s method table 3. set ⟦I⟧'s superclass to the ⟦C⟧'s singleton class's superclass 4. set ⟦C⟧'s singleton class's superclass to ⟦I⟧ In other words: create an anonymous class with the same methods but a different identity as the mixin and insert it in the ancestor chain directly above the singleton class. There's really no need here for ⟦M⟧ to be a module, it could just as well be a class. The linearization property depends on the fact that mixin inclusion is done via a freshly minted anonymous class which has no ancestors or descendants of its own: the include class ⟦I⟧ *only* gets the methods from the mixin, it does not get its place in the inheritance hierarchy. Whether the method table that ⟦I⟧ points to used to belong to a module or a class is really irrelevant. It's just a bag of methods. The case of mixing in a mixin into another mixin is also handled similar to the way it is today: currently, when you mix a module into a module, it gets inserted above the module like it would above a class. And then, when you mix a module ⟦M⟧ into a *class*, Ruby not only constructs an include class for the ⟦M⟧'s method table, but recursively also for all modules mixed into ⟦M⟧. Note that this means that this mixin chain is only walked *once*, when you include ⟦M⟧ into the class. If you later mix other modules into ⟦M⟧, their methods will *not* be available to instances of the class. Again, it would be possible to do just the same thing with classes instead of modules: walk the chain of include classes and simply clone them, then inject them into the ancestors chain like above. That's what I meant by "makes perfect sense": you can take the exact same algorithm that Ruby currently uses for module inclusion and use it for class inclusion with the exact same results. jwm
From: Rick DeNatale on 23 Jun 2010 10:34 2010/6/22 Jörg W Mittag <JoergWMittag+Ruby(a)googlemail.com>: > Gary Wright wrote: >> On Jun 21, 2010, at 3:35 PM, Jörg W Mittag wrote: >>> Eric MSP Veith wrote: >>>> Modules are used for mixins. Is it possible -- and does it make sense at all >>>> - -- to mixin a class into another class? I guess not? >>> Actually, to add a bit to Brian's answer: it *is* possible and makes >>> perfect sense. It's just not allowed in Ruby, but it *is* allowed in >>> other languages. > You can take the algorithm Ruby uses for mixins and simply substitute > classes for modules and it would work exactly the way it does today, > including the linearization property. > > The way mixins work in Ruby is (roughly) as follows (assume that we > want to mix â¦M⧠into a class â¦Câ§, ignore for a moment the case of > mixing a mixin into another mixin): > > 1. create an anonymous class â¦I⧠Some would quibble with calling this an anonymous class instead of an anonymous module, but that's a quibble. > 2. set â¦Iâ§'s method table pointer to â¦Mâ§'s method table > 3. set â¦Iâ§'s superclass to the â¦Câ§'s singleton class's superclass > 4. set â¦Câ§'s singleton class's superclass to â¦I⧠> > In other words: create an anonymous class with the same methods but a > different identity as the mixin and insert it in the ancestor chain > directly above the singleton class. > > There's really no need here for â¦M⧠to be a module, it could just as > well be a class. The linearization property depends on the fact that > mixin inclusion is done via a freshly minted anonymous class which has > no ancestors or descendants of its own: the include class â¦I⧠*only* > gets the methods from the mixin, it does not get its place in the > inheritance hierarchy. Whether the method table that â¦I⧠points to > used to belong to a module or a class is really irrelevant. It's just > a bag of methods. > > The case of mixing in a mixin into another mixin is also handled > similar to the way it is today: currently, when you mix a module into > a module, it gets inserted above the module like it would above a > class. And then, when you mix a module â¦M⧠into a *class*, Ruby not > only constructs an include class for the â¦Mâ§'s method table, but > recursively also for all modules mixed into â¦Mâ§. Note that this means > that this mixin chain is only walked *once*, when you include â¦M⧠into > the class. If you later mix other modules into â¦Mâ§, their methods will > *not* be available to instances of the class. > > Again, it would be possible to do just the same thing with classes > instead of modules: walk the chain of include classes and simply clone > them, then inject them into the ancestors chain like above. > > That's what I meant by "makes perfect sense": you can take the exact > same algorithm that Ruby currently uses for module inclusion and use > it for class inclusion with the exact same results. There's a lot of truth in this, but I think there are some subtleties. Mixing in a class like this would support inheriting instance methods from the mixed-in class, but not class methods. One of the differences (and they are pretty small) between classes and modules in Ruby is that if a class subclasses another, the subclass object inherits the class methods from the superclass. Modules don't have "super modules" so a mechanism for this isn't needed in the implementation. Now I suppose this could be handled by doing something similar to the ancestry chain of the metaclass of the subclass, but personally, I don't think this whole idea of mixing in classes is really that attractive a feature. -- Rick DeNatale Blog: http://talklikeaduck.denhaven2.com/ Github: http://github.com/rubyredrick Twitter: @RickDeNatale WWR: http://www.workingwithrails.com/person/9021-rick-denatale LinkedIn: http://www.linkedin.com/in/rickdenatale
From: Caleb Clausen on 23 Jun 2010 22:27 On 6/22/10, Jörg W Mittag <JoergWMittag+Ruby(a)googlemail.com> wrote: > Gary Wright wrote: >> On Jun 21, 2010, at 3:35 PM, Jörg W Mittag wrote: >>> Eric MSP Veith wrote: >>>> Modules are used for mixins. Is it possible -- and does it make sense at >>>> all >>>> - -- to mixin a class into another class? I guess not? >>> Actually, to add a bit to Brian's answer: it *is* possible and makes >>> perfect sense. It's just not allowed in Ruby, but it *is* allowed in >>> other languages. >> Allowing classes to mixin other classes would change the class >> hierarchy from a tree to a directed acyclic graph. As soon as you >> do that you have to figure out how to manage the method lookup >> process along multiple paths. I don't think there is any sort of >> consensus on how to do that (i.e. different languages take >> different approaches) and so I'm not sure 'makes perfect sense' is >> an accurate characterization of the solution space for that >> problem. > > You can take the algorithm Ruby uses for mixins and simply substitute > classes for modules and it would work exactly the way it does today, > including the linearization property. > > The way mixins work in Ruby is (roughly) as follows (assume that we > want to mix â¦M⧠into a class â¦Câ§, ignore for a moment the case of > mixing a mixin into another mixin): > > 1. create an anonymous class â¦I⧠> 2. set â¦Iâ§'s method table pointer to â¦Mâ§'s method table > 3. set â¦Iâ§'s superclass to the â¦Câ§'s singleton class's superclass > 4. set â¦Câ§'s singleton class's superclass to â¦I⧠> > In other words: create an anonymous class with the same methods but a > different identity as the mixin and insert it in the ancestor chain > directly above the singleton class. > > There's really no need here for â¦M⧠to be a module, it could just as > well be a class. The linearization property depends on the fact that > mixin inclusion is done via a freshly minted anonymous class which has > no ancestors or descendants of its own: the include class â¦I⧠*only* > gets the methods from the mixin, it does not get its place in the > inheritance hierarchy. Whether the method table that â¦I⧠points to > used to belong to a module or a class is really irrelevant. It's just > a bag of methods. > > The case of mixing in a mixin into another mixin is also handled > similar to the way it is today: currently, when you mix a module into > a module, it gets inserted above the module like it would above a > class. And then, when you mix a module â¦M⧠into a *class*, Ruby not > only constructs an include class for the â¦Mâ§'s method table, but > recursively also for all modules mixed into â¦Mâ§. Note that this means > that this mixin chain is only walked *once*, when you include â¦M⧠into > the class. If you later mix other modules into â¦Mâ§, their methods will > *not* be available to instances of the class. > > Again, it would be possible to do just the same thing with classes > instead of modules: walk the chain of include classes and simply clone > them, then inject them into the ancestors chain like above. > > That's what I meant by "makes perfect sense": you can take the exact > same algorithm that Ruby currently uses for module inclusion and use > it for class inclusion with the exact same results. What you describe might work well enough for pure-ruby classes, but if you tried to mix a core class (Array, String) into another class, the result would be segfaults. Maybe the same would be true of any class implemented in C? Not sure.
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 Prev: Doubt regarding Testing with RSpec. Next: General Confusion |