--000e0cd247467ff7080465539259 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit > The set of expression classes is finite. In my extension to Runt, I > need to add some behavior to the TExpr module which I do with another > mixin. I didn't want to have to worry about which classes mixin the > TExpr, I just wanted to modify(aka extend) the TExpr module like you > would any ordinary class and have it be reflected in all classes who > included this module. The alternative(which is what I'm ending up > doing) is to loop through all the classes of Runt and check the > ancestors for TExpr and if so, include my extension module directly > into the class. This approach seems yucky to me and not in the spirit > of ruby and really OO design. Yes, this is very yucky and you shouldn't have to do it. Unfortunately I can't think of any elegant way to do this without inspecting the class tree using your method or ObjectSpace (you can't get the descendants of a module directly, so I use ObjectSpace which is kinda expensive). > You can clearly argue with me whether you think extending a module > with another is appropriate or not in the above case. However, the > issue remains that this behavior is not consistent with the rest of > ruby. I point again to the fact that you can change behavior of a > module directly and it will be reflected by all included classes - > however NOT if you change behavior via including another module. You ought to be able to just say you want to change all the objects of such-and-such a type, whether that type is a module or a class. You could of course put your new methods straight into TExpr, which would work but could cause debugging and other monkey-patching issues. It's up to you whether you consider this a problem. > > Also, I don't necessarily(keyword here) agree with the philosophical > point of needing 'a lot' of use cases to implement a feature. I am very much speculating here, but I'd be surprised if this weren't a case of, not implementing something as such, but rather one of removing special cases. One way to implement Ruby's object system is that you construct the whole thing out of modules (a module is an object that has one method table and zero or more 'parent' modules), then things like parent-child inheritance and singleton classes can be implemented on top of that. This ends up being quite elegant and I suspect this is a performance issue. Far as I know, Ruby finds methods by getting a list of an object's ancestors and extracting all implementations of the method from those modules. Walking up a series of parent classes takes linear time so it's not expensive for classes to see stuff added to their parents, but walking and flattening a multiple inheritance tree could be exponential time so it makes sense to cache ancestor trees when things like #include are called, effectively blocking a class from seeing changes to its mixins' ancestry. If anyone knows how Module/Class are really implemented in MRI I'd love to know more about it (also: I really need to learn C). -- James Coglan http://github.com/jcoglan --000e0cd247467ff7080465539259--