From: Jim Weirich Date: 2005-07-29T12:04:39+09:00 Subject: Re: What's so special about operators, built-in classes and modules? [Warning ... I'm afraid I got a bit long winded ... sorry] On Thursday 28 July 2005 10:00 pm, Daniel Brockman wrote: > I'd appreciate it if someone could clarify once and for all > how the diamond inheritance problem doesn't exist in Ruby. First, some clarification: What is the problem with diamond inheritance? Diamond inheritance is a pattern of MI that has a parent class (or module in Ruby's case) that is reachable via different inheritance paths. The specific term for this is Repeated Inheritance. The basic problem with Repeated Inheritance is how instance variables defined in the repeated class should be handled. Should there be one copy total, or one copy for each repeated parent class. (An aside: Another thread on this topic indicated that method resolution was a problem in repeated inheritance. That is incorrect, it is an issue in any form of multiple inheritance (even the module variety), and does not specific to repeated inheritance). Ok, now that we've clarified the question, we can answer it: Why isn't repeated inheritance a problem with modules? Some people will say its because modules don't define state. Although correct, its misleading because it implies that classes do define state. Classes (in Ruby) don't define state either. Wait a minute, let me say that in a better way! Module (and Classes) in Ruby don't contain any /instance/ state. The instance variables in a ruby object are managed by the instance itself, not the classes. This is different from most other OO languages. Most other languages think of objects as little areas of memory. Consider a class B that inherits from A. Its memory layout would look something like this: |<--- A --->| |<------------- B ------>| The memory for the A part of the object takes up the first section of memory of a B object. In fact, someone looking at the beginning of the B object would see a real, live A object in memory. That's how polymorphism works in languages like C++. When you have repeated inheritance, the whole memory layout scheme gets all screwed up. Lets introduce two new classes, C which also inherits from A, and D which multiply inherits from B and C. What does the memory layout of D look like? |<--- A --->| |<--- A --->| |<------------- B ------>|<------------- C -------->| |<------------------------------------------------------ D --->| Yep, two copies of A. One for B and one for C. And that's the problem. Most times you only want one copy of A. Different languages handle the repeated inheritance differently. C++ introduces "virtual" inheritance, where the base class is not located in the same memory area, but is (possibly) displaced. Java only allows MI in interfaces (and since interfaces have no data memory layout, the problem doesn't arise). Eiffel has a flexible approach to repeated inheritance. Any feature (Eiffel's term for methods and instance variables) that ends up with the same name in the final class, gets only one copy of that feature. You can rename features as you inherit, so if a feature ends up with two names in the final class, you get two copies of it, each with its own name (so there is no ambiguity either ... very clever). Eiffel's solution is very clean for the developer, but really hard to implement correctly. Getting back to Ruby ... The whole memory layout problem is brought about by thinking of variables as shoeboxes which hold values. Once you have shoeboxes, you got to pay attention to how you arrange them. Ruby objects don't have a memory layout for the instance variables. In fact, it is quite possible that two objects of the same class don't even have the same instance variables. So, in summary, why is diamond (repeated) inheritance not a problem in Ruby modules? Because the memory layout issues that force multiple copies of a base class just don't exist in Ruby. -- -- Jim Weirich jim@weirichhouse.org http://onestepback.org ----------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)