Tag: module

Playing with Ruby modules: prepend

In the past month or so I’ve been learning Ruby, this is my first blog post about the language and my experiences learning it. I’d love to hear your feedback.

Ruby allows you to work with modules and mixins, giving characteristics to classes and instances that otherwise could only happen through inheritance. One can argue that there are many similarities between Ruby’s mixins and PHP’s traits.

But first things first: what is a mixin? A mixin is a module that you include in a class, because you are “mixing in” the module methods with the instance methods of a class.

When learning about Ruby’s modules behavior, specifically the include functionality, I couldn’t help but think how similar it was to PHP traits. It reminded me how a class can override an inherited method from a trait, or just plain inheritance of new features that class didn’t have before.

What I learned was the following:

  • classes that extend a module have methods from it, however they are only accessible through a class call
    • extend doesn’t change the inheritance chain
  • classes that include a module have methods from it, however they are only accessible through an instance call
    • include does change the inheritance chain
  • and, finally; prepend. Which is a funny case in my opinion, a bit trickier to grasp the concept at first sight. But I got a bit more understanding after playing with the following. I think…

Prepend

I learned about the existence of prepend after doing this small exercise. Before this I thought you either extend a module or include it.

Try out the following code:

What should we get when calling #color?

car = Car.new
car.color

The naive me, thought in the beginning the result would be:

# Red
# => nil

And my reasoning was, except for monkey patching, isn’t Car overriding everything because when instantiated we overload the method #color? To my surprise, it printed (come on, go check it!):

# Blue
# => nil

Apparently I was wrong. Playing with pry I added super (LOC4) to Vehicle#color, convinced that the return would be Green, since Car inherits Vehicle, right? Wrong again!

It looks like, Paintable is overriding Car, which is a bit confusing because the keyword is prepend, for all I know (and the dictionary too, trust me, I checked) it means to attach something in the beginning of something else.

With that in mind, shouldn’t Paintable come before Car, and because I have overridden #color in Car (LOC17), shouldn’t Car have the last say in what color should be?

Apparently, no. The correct way to read it is:

Paintable is prepending the inheritance chain of Car

And this is why:

Which means that when calling #color in the instance we get Blue and why super prints Red, since Printable now has Car as a superclass.

Conclusion and Use Cases

Modules add functionality to your class, either by being a mixin or through class methods when you extend it.

I found this blog post with a good example of inheritance vs mixins:

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 Pokemon class.

When a class should be capable of something, you should use a Mixin. For example, DVD, MP3, and 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

Keeping the Car example, the Paintable module makes more sense to be used with an extend, since you can change colors not only of cars, vehicles, multiple types of objects that won’t necessarily inherit Vehicle.

Also, beyond including, and extending a module you can prepend it. prepend changes the inheritance chain as does include, but with inverse order. extend does not change the inheritance chain.

You will be want to use prepend whenever you want your code to be executed before the class. After working with so many legacy applications, I can see this being really useful when you want to extend the functionality of some class, let’s say Login, you want to run before Login a check to see if the requester address is accessing only through your closed network, prepend would allow you to do that. And a good side effect of using prepend is that you remove the necessity of directly monkey patch a method.

I think only experience will make clear the best way to implement a certain module in an application, but understanding how each of these tools behave is important before you can make that decision.