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?
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 A
∪ B
, and the methods of A
∪ B
∪ C
. 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
, A
∪ B
, A
∪ C
, B
∪ C
, and A
∪ B
∪ C
. 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, String
s 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: Numeric
s are Comparable
but not Enumerable
, Array
s 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With