From: Gregory Brown Date: 2007-01-20T09:37:44+09:00 Subject: Re: inheritance concept in ruby Hi Helder, sorry it took me a while to get back to these questions, but I've done what I could to answer them below. I can't remember where in the thread you talked about a class hierarchy vs. a mixin hierarchy. The thing is, though it is likely you'll end up on a long chain of subclasses in a complex system, it's unlikely you'll run into a deeply nested set of modules. Even when you do, these modules will typically implement things that are orthogonal from each other, so you can still look at any given module as a distinct unit living outside of the class heirarchy. Once mixed in, it more or less becomes part of the class definition, and the call order is pretty intuitive in practice. The same cannot be said for Multiple Inheritance unless the system is designed with much care. That's the core of the reasoning behind modules as far I can tell, and the responses that follow have that in mind... On 1/16/07, Helder Ribeiro wrote: > > I'm not sure you really mean class method here. What you're saying is > > true of any time you send a message to an object -- that is, it looks > > in its class, then the modules, etc. > > Yes, i meant any method call. But I haven't found this lookup order > stated in its full anywhere else. The part after the "*and*" is what I > inferred from what the PickAxe says about the other cases (the quote is > in this thread somewhere). Perhaps we need to document this better. I'm not sure where the best place would be, though. > But this is an artificial difference, because you can define a lookup > order to solve this conflict without the need for Modules. So the > question is > > "since Ruby already has a well-defined lookup order that takes care of > conflicts in class/module hierarchies, couldn't you have a similarly > well-defined lookup order for Multiple Inheritance and do away with > Modules altogether?" Probably. But the question is, why would you want to do this? I suppose what would be important to know is whether this interest in the system is of theoretical or practical grounds for you. If it is of theoretical grounds, these are all valid questions, but I do think they'd end up somewhere around the 'this is how matz implemented them, so unless something Really Wrong with them can be shown, they're here to stay' conclusion. It is good to talk about these things because it lets us understand better how they work, but I'm not sure that I've seen many cases *for* MI in ruby. Since we seem to be getting along fine without them, the whole "If it ain't broke, don't fix it" adage applies. If your interest in this is based on a practical modeling issue, I think it'd be better for you to describe the model that you are dealing with so we can help you think of ways to express it cleanly in Ruby. Perhaps seeing the way modules are used in practice would help clear some of the fuzzy areas up for you. > > There's still the possibility of name collision with mixins, but there > > are (to my knowledge) no special cases, no need for tie-breaking rules > > -- because the rules that are there in the first place make a tie > > impossible. > > Don't understand what you're saying. There is, indeed, no need for > tie-breaking rules if you have lookup order rules (i'm assuming those > are what you mean by "the rules that are there"). It happens that they > are the same, though, you're just giving them different names. Tie breaking rules are necessary when you end up with cycles in the graph. The MRO for Python 2.3 is pretty straightforward, mostly because it fails if this occurs (preventing the need for complex tie breaking rules). http://www.python.org/download/releases/2.3/mro/ With mixins however, there is no situation where this would occur, which is one of it's strengths. > > > > > The only thing holding me from saying "it's a tree, *connected* to a > > > general network, thus it's all a big network" is that the connection > > > seems to be unidirectional (modules can't have classes 'mixed in' or > > > inherit from them, I suppose). Is there some theoretical result that > > > bases itself on this (or some other thing, I dunno) to say that there > > > is a clear distinction between the M.I. model and the "tree + > > > pan-inheritance-modules"? Actually, multiple inheritence is meant more-or-less to solve the same problem, to unify orthogonal concerns. To me it's just a cleaner system to accomplish the same basic goal, while providing a little bit more protection against shooting yourself in the foot. However, the same problems can indeed arise from both, I just think the mixin model puts you in a mindframe that discourages that. (One you get used to how it works) > > > Furthermore, if both models are almost (or perhaps completely) > > > equivalent *and* the only problem is with the limited case of name > > > collision and that can be solved with lookup rules, where is the source > > > of contention? Why would people favor one over the other? > > The thing I like about modules is that I find the model a suggestive > > way of thinking about domain modeling. I like having both a noun-like > > thing (classes) and an adjective-like thing (modules). > > Then again, > > all of this is purely in the context of Ruby; I don't inherently like > > one or the other more. > > So the difference is only in the way you think about those two things > (classes and modules)? Or do they have some difference in their > inheritance behavior that makes you think multiple inheritance would be > unsuitable for what you do (I know nothing about domain modeling)? This is mostly a style thing. If you think of some module names, you get things like Comparable and Enumerable. Now let's put that in the context of use with classes. Some object is an Array. That Array is Enumerable. Some object is a Fixnum. That Fixnum is Comparable. So just like using any concept to organize your code, on it's own, there is little technical difference. But it is very powerful when you use the concepts right. You say, hmm... I'm looking at a relationship in which this chunk of code describes the kinds of things you can do with an object if it meets certain criteria, that sounds like a module would make sense. Or, this object embodies something rather concrete with unique behaviors, perhaps a class would be appropriate. Sometimes this changes as you go through your development process. Sometimes you realize you only needed a module and you used a class. Or sometimes the opposite happens. So it's not like Ruby is forcing your hand to do one or the other. The relative similarities between the two make it somewhat easy to refactor from one to another without changing much.