When you first get started with the Ruby programming and you come from a different language, the only tricky piece is often Ruby’s approach to block/closure/anonymous functions. Sure the metaprogramming seems a bit odd, but you don’t have to use it. That’s why a lot of developers think that Ruby is a simple language. Turns out that when you dig a bit further, you realize that Ruby is actually quite a complex language. Ask any developer who worked on a Ruby implementation, they’ll all tell you the same thing: Ruby is full of small little things that makes it complicated.
An example of something that might seem simple is inheritance. Ruby, unlike C++, doesn’t support multiple inheritance. What that means is that a Ruby class can only have 1 parent class (superclass). However multiple inheritance can be achieved via modules used as a mixins. That’s a very common pattern, people put some code in a module and then mix it in/include it in a bunch of classes. The problem I see though, is that people abuse these concepts and don’t respect the difference between a class, a module and a module used a mixin.
Object Oriented Programming 101:
“In object-oriented programming, a class is a construct that is used to create instances of itself – referred to as class instances, class objects, instance objects or simply objects. A class defines constituent members which enable its instances to have state and behavior.”
So if you create a class and you don’t create instances, you are using the wrong construct. Here is an example of what I often see:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Which can be used as such:
1 2 3
(granted this isn’t a great example since we could have used a subclass
Hash but just bear with me)
Actually, the developer who wrote the code above would probably also use
some Ruby magic like
method_missing to provide a more laxed API and allow for “nicer” getters
Settings['secret']. I have my
own thoughts on the topic but it’s
an entirely different subject.
Note also that the way class level methods are defined can also be different depending on who wrote the code, you might see the following variations (and other more esoteric ones):
1 2 3 4 5 6 7 8 9 10
Settings code above works, the code is simple, yet I will argue one thing: it’s
an abuse of the class construct. We’re breaking the #1 rule of classes:
“create instances of self”.
It’s easy, whenever you don’t create instances of a class, please don’t use a class.
That’s also true for slightly different examples such as:
1 2 3 4 5 6 7
There is no need whatsoever to create an instance of
API, using a class is
picking the wrong construct. Also, I don’t care if you use the
module to only allow 1 instance of the class, you still shouldn’t use a
class in the above example.
In Ruby’s object hierarchy, the Class object actually inherits from the Module object.
1 2 3
As per Ruby’s source code defintion:
“A Module is a collection of methods and constants.”
I like to think of modules as namespaced methods and constants. Whenever you want code that logically belongs together but that won’t require that you create instances of a ‘model’, then a module is the right construct to use.
As a matter of fact, the two examples above are great cases where a module should have been used.
The confusing bit is that modules can have module level methods but also instance level methods. Here is an example:
1 2 3 4 5 6 7
This is a module level function, it could also be written like that:
1 2 3 4 5 6 7 8 9
And be used like that:
Until now, it makes sense. The weird thing is that even though, modules unlike classes aren’t meant to create instances, we have the possibility to define module instance methods.
1 2 3 4 5 6 7 8 9 10 11 12 13
Great, but we can’t actually use these methods since they are instance methods and we don’t create instances of modules. Well, that isn’t quite true, there is a way to access them and that’s by using a module as a mixin. What that means is that we inject/copy the module code inside a class or an(other) object. Example in code:
1 2 3 4
Or we can add the code to a class so the instances of this class can access our module instance methods:
1 2 3 4 5 6
The mixin modules
There a plenty of resources online about the many ways to use mixins in Ruby to achieve multiple inheritance and do cool stuff. But the point of this article is to try to demonstrate that mixins shouldn’t be abused.
My problem with the above example is that by mixing in the
module inside our
Foo class, we created an uneeded, confusing extra
level of abstraction. Instances of
Foo now have access to two
secret_key. These methods or the
objects they refer to don’t belong to the
Foo class, but it seems
convenient to not have to type
Settings.repository so we mixed things
in. Plus, a lot of Ruby developers seem to dislike adding class/module
level methods so they feel that this approach ‘feels better’.
Here is the thing, the convenience of typing a few less characters isn’t
worth it. Next time you or someone else will look at an instance of the
Foo class calling
repository, finding where it is defined is going
to be a pain. That’s especially true if you have many mixins in your
Settings will also probably grow and you will end up with a
bunch of methods that have nothing to do with your class instances.
In this case, I will call the use of a mixin, an abuse of construct.
Sure, Ruby allows you to do it, but that doesn’t mean it’s the right
thing to do. In Ruby, unlike in Python, there are 101 ways to do a
simple thing. It doesn’t mean that the 101 ways are good, it just means
that Matz wasn’t sure how people would use his programming language and
chose to give us more freedom to messup/doing it our own way.
When to use mixins?
I have my own rule: use mixins whenever you need to share behaviors between different classes.
In the above example, we weren’t sharing behaviors, we were sharing objects, there was no need to actually use a mixin.
That said, rules aren’t rules without exceptions. A good example of this
exception would be the
Math module from the standard library.
This module offers trigonometric and transcendental functions. You might
think that this module would be designed to be a mixin so you can get
exp and friends available in your math related classes.
It turns out, all Math’s methods are defined a module functions meaning
that they are meant to be called from the
Math module directly.
However, Ruby allows you to mixin module functions, but these functions
become private. If you do include the module inside your class, your instance methods
will be able to call
hypot(x,y) directly, but these methods won’t be
available from the outside (
Foo.new.log(42) would raise an
To conclude with mixins: mixins are great but don’t abuse them or you
will endup with so much abstraction that your coworkers will secretely
call you Kandinsky.
Stick to simple mixins allowing you to share behaviors between at least
a couple classes. See
DataMapper for a great way to use mixins.
Modules: your secret functional programming weapon
I have to say that I do like functional programming. The idea of having functions not mutating the states of things around them pleases me. It just seems clean, you feed data to a function and you get another piece of data. No states were changed, maybe some temporary variables were allocated to process the data, but the only thing that matters is the input and the output. Easy to grasp, easy to follow, no magical states being changed by some code fairies.
The good news is that Ruby allows us to write code like that. And this
is where modules are great. Very much like the
Math module we
discussed above, there are many cases where you want to have a bunch of
functions that process an input and provide an output without keeping
any states. A good example of such a module would be a param
verification filter. The filter takes an input, takes some rules and
verifies that the input matches the rules.
Surely, we could create an instance for each verification, this would
allow to keep states in our class and do the usual OOP things. But we
could also simply use a module with a bunch of module (level) functions
that would pass to each other the input they need to not need to keep
states. The end result will be faster, nicer on the GC and easy to
Mixing OOP and functional programming isn’t new, ask Scala developers! If done right, by adopting this approach we can simply our code base, make it faster, easier to maintain and not losing the chance to also use OOP paradigms when needed.
As shown earlier, modules and classes have pros and cons. Classes are
however much more natural to use for Object Oriented Programming. A
compromise about the
Settings examples was suggested by Evan Phoenix.
The solution is elegant and simple. Use a class and an instance.
Here is an implementation based on his suggestion:
1 2 3 4 5 6 7 8
The point here is not about the class implementation but that fact that we use a class and associate an instance of this class to a constant so it can be shared all over the place. Wow, a constant, this is so nasty you might think. Classes are constants too and so are modules, here we just allocate an instance of a class to a constant. Surpisingly simple and efficient.