--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--