From: Rick DeNatale Date: 2010-06-23T23:34:34+09:00 Subject: Re: Namespacing a class 2010/6/22 Jörg W Mittag : > 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