From: "Jörg W Mittag" Date: 2010-06-23T11:10:06+09:00 Subject: Re: Namespacing a class 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