Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using multi-level inheritance instead of ruby mixins

Here is an example of multi level inheritance in ruby, here we have 3 classes A, B and C. B inherits from A and C inherits from B, so at the end class C has all methods of A, B and C.

class A
  def hello_by_a
    puts "A says hello"
  end
end

class B < A
  def hello_by_b
    puts "B says hello"
  end
end

class C < B
  def hello_by_c
    puts "C says hello"
  end
end

c = C.new
c.hello_by_a #=> A says hello
c.hello_by_b #=> B says hello
c.hello_by_c #=> C says hello

p c.methods-Object.methods #=> [:hello_by_c, :hello_by_b, :hello_by_a]

And here is the same thing as mixins, here instead of classes A and B, we have modules A and B which gets included to class C. Now class C has all 3 methods

module A
  def hello_by_a
    puts "A says hello"
  end
end

module B
  def hello_by_b
    puts "B says hello"
  end
end

class C
  include A
  include B

  def hello_by_c
    puts "C says hello"
  end
end

c = C.new

c.hello_by_a #=> A says hello
c.hello_by_b #=> B says hello
c.hello_by_c #=> C says hello

p c.methods-Object.methods #=> [:hello_by_c, :hello_by_b, :hello_by_a]

At the end if we do it in both ways class C will have all the methods of class A and B or module A and B. So why is it better to use modules instead of multilevel inheritance with classes?

I know we should use mixins but don't really know why we shouldn't use multilevel inheritance like above. What are the disadvantages and advantages. if any?

like image 245
vishless Avatar asked Sep 20 '19 16:09

vishless


1 Answers

Two main reasons:

You can only inherit from one class, but you can mix in as many mixins as you want. This means that inheritance is extremely "expensive" in the sense that if you are forced to use inheritance, you are forced to "use up" 100% of your "inheritance resources".

You can compose mixins any way you want. In your example, I can only get the methods of A, the methods of AB, and the methods of ABC. I can, for example, not get only the methods of B. With mixins, I can compose them in any combination: only A, only B, only C, AB, AC, BC, and ABC. I can also compose them in any order I want: I can have the methods of C override the methods of B or I can have the methods of B override the methods of C.

I can easily imagine an object that is both Enumerable and Comparable. (For example, Strings are Comparable and before Ruby 1.9, they also used to be Enumerable.) In your proposed world, this would only be possible if either Enumerable inherits from Comparable or Comparable inherits from Enumerable. However, this will not work: Numerics are Comparable but not Enumerable, Arrays are Enumerable but not Comparable.

There is also a more philosophical / semantic reason: enumerability and comparability are completely orthogonal concepts, why would you tie them together so closely? Inheritance is one of the closest forms of coupling we have, tying two concepts to closely together that don't actually have anything to do with each other, is just wrong.

like image 126
Jörg W Mittag Avatar answered Oct 23 '22 18:10

Jörg W Mittag