Ruby Mixins
Mixins are the Ruby way to eliminate the need for multiple inheritance. In short, a class can "mixin" multiple modules, which in practice means that it gains either the instance or class methods defined in the mixed in module, depending on how it was mixed in.
This has some benefits. When a an objects method gets called, it is clear in what order the interpreter will search for that method (see a more detailed discussion), thereby avoiding the "Deadly diamond of death" problem.
Let's look at some code to clarify this.module A
def stuff
puts "Hi, I'm module A"
end
end
module B
def stuff
puts "Hi, I'm module B"
end
def is_a?(_class)
"B#is_a?"
end
end
class First
include A
include B
end
class Second
include B
include A
end
class Third
def stuff
puts "Hi, I'm class Third"
end
include A
include B
end
class ThirdChild < Third
end
First.new.stuff # Hi, I'm module B
Second.new.stuff # Hi, I'm module A
Third.new.stuff # Hi, I'm class Third
puts ThirdChild.new.is_a?(First) # B#is_a?
Finally, the instance of ThirdChild returns the "B#is_a?" string when its is_a? method is called. It is easy to jump to the conclusion that it should call Object#is_a? and return false. However, it's first ancestor, Third, has mixed in module B, and has therefore overridden the Object#is_a? method.
Mixins are a powerful tool, in particular to DRY up code. A common example of its benefits is to mixin the Comparable module and get several comparison methods by implementing a single method (<=>). But mixins should be used with care.
Whenever you mixin a module, you are increasing the complexity and surface of that object. Added complexity means that it is more likely to contain bugs. You also need to think hard about whether the mixin violates the single responsibility principle (and if so, is the violation worth the benefits?).