Jul 08, 2015
Table of contents:
Over the last couple of weeks we’ve looked at a couple of important concepts when working with Classes in Ruby such as Inheritance and using Modules.
Ruby is a programming language that only allows single inheritance. This means a class can only inherit from one parent class.
However, there are a lot of situations where it would be advantageous to “inherit” functionality from multiple places.
Fortunately Ruby provides this functionality as Mixins. In today’s tutorial we are going to be looking at using Mixins, why you would use them and when you should use them over classical inheritance.
A Mixin is basically just a Module that is included into a Class. When you “mixin” a Module into a Class, the Class will have access to the methods of the Module.
If you are familiar with PHP, a Mixin is essentially the same as a Trait.
A couple of weeks ago we looked at the difference between Class Methods and Instance Methods.
The methods of a Module that are mixed into a class can either be Class Methods or Instance methods depending on how you add the Mixin to the Class.
To add Module methods as instance methods on a Class you should include the Mixin as part of the Class.
For example, imagine you had this incredibly useful Module:
module Greetings def hello puts 'Hello!' end def bonjour puts 'Bonjour!' end def hola puts 'Hola!' end end
To add these methods as instance methods on a class, you would simply do this:
class User include Greetings end
Now you will have access to the methods on any instance of that Class:
philip = User.new philip.hola # => Hola!
But if you try to call the methods as Class Methods, you will get an error:
User.hola # => undefined method 'hola' for User:Class (NoMethodError)
To add Module methods as Class Methods, instead of using
include you would use
class User extend Greetings end
Now you can call the methods on the Class:
User.hola! # => Hola!
But not on an instance of the Class:
philip = User.new philip.hola # => undefined method 'hola' for #<User:0x007fbd5b9ae438> (NoMethodError)
When you create a new instance of a Class, the
initialize method will automatically be invoked.
When you include a Module in a Class, the
included method will be invoked on the Module.
This makes it very easy to add both Instance Methods and Class Methods using a pattern you will see a lot in Ruby code.
For example, imagine we have the following
module Utilities def method_one puts 'Hello from an instance method' end module ClassMethods def method_two puts 'Hello from a class method' end end end
In this example I’ve separated the Class Methods into their own nested module. You don’t have to name the module
ClassMethods, but this is the convention you will see being used.
Next we can implement the
self.included hook that will be automatically called whenever this module is included in a Class:
def self.included(base) base.extend(ClassMethods) end
This method will receive the instance of the Class that is being instantiated. Inside of the
included method we use the
extend method to add the
Now when we include this module in a Class we have access to both the Instance Methods and the Class Methods:
class User include Utilities end User.new.method_one # => Hello from an instance method User.method_two # => Hello from a class method
So hopefully it’s clear as to how to use a Mixin, but an important question is why you would want to use a Mixin?
Mixins are perfect when you want to share functionality between different classes. Instead of repeating the same code over and over again, you can simple group the common functionality into a Module and then include it into each Class that requires it.
Another important thing to understand is, when do you use a Mixin over normal Inheritance?
As I mentioned in Understanding Inheritance in Ruby, Inheritance has a lot of semantic meaning within the hierarchy of an application. There is a good reason why you can only inherit from a single parent.
Inheritance means that a class is a “type of something” and suggests specialisation. For example, a
Pikachu object is a type of
Pokemon and so it makes sense to inherit from the
When a class should be capable of something, you should use a Mixin. For example,
Bluray classes all have the
play method, but just because they are all capable of the same action, does not mean they all should inherit from the same parent.
The difference is subtle, but extremely important. If it’s not immediately clear, don’t worry! With experience you will begin to understand the difference and why it is so important.
Modules are an important part of the Ruby programming language and they are something that you will see being used extensively in almost every non-trivial example of Ruby code you will see.
The concept and implementation of Modules is really very easy once you understand their purpose and what benefits they introduce.
The difference between using a Mixin and using Inheritance is slightly more tricky, but it’s one of those Computer Science concepts that is universally applicable.