From: Paul Brannan Date: 2002-04-09T08:59:25+09:00 Subject: Re: Mixins vs. Multiple Inheritance On Wed, Apr 03, 2002 at 04:47:30AM +0900, Jason Voegele wrote: > Given that including a module M into a class C > > * Mixes in all methods from M into C > * Results in C#is_a?(M) to be true > * Does not resolve name collisions > > how is mixing in multiple modules really any different from standard > multiple inheritance? > > I suspect that it has something to do with repeated (i.e. "diamond") > inheritance structures, but I don't see how modules resolve this issue > either. > > What are your thoughts? If I have the traditional diamond inheritance: Base / \ Left Right \ / Derived then there are a few important differences between C++ MI and Ruby mix-ins: 1) Ruby simplifies this inheritance to look like: Derived < Right < Left < Base 2) In C++ MI, Right::foo cannot call Left::foo, but with Ruby mix-ins, this is possible. 3) As someone else stated, mixins are used for implementation inheritance, while C++ MI can be used for either interface or implementation inheritance. Other languages differ on this. Ruby has little use for interface inheritance. 4) Note that Python handles this a bit differently. In older Python, Derived::foo calls Left::foo, which calls Base::foo. Newer Python (2.2) is more like Ruby, since Derived::foo visits classes in the order Derived, Left, Right, Base (it visits in the order Derived, Left, Base, Right, Base, but removes all but the last occurance of duplicated classes). (see http://www.amk.ca/python/2.2/). 5) Ruby also has no notion of non-virtual inheritance, so it is not possible to get two copies of Base without some really odd code. 6) Mixing in a module in Ruby can actually cause code to be executed. This doesn't happen with Ruby's inheritance (correct me if I'm mistaken here) or with C++'s MI. Ruby modules can have knowledge about who included them, but C++ classes can't know who inherited from them (though perhaps I'm wrong here; many strange things can be done with template meta-programming). In a previous thread, I stated that it is not possible for Derived::foo to call Base::foo, but I have since learned that it is possible: d = Derived.new m = Base.instance_method(:foo) m.bind(d).call() See [ruby-talk:22139] for more on the subject. Paul