An introduction to modules : Part 2

In the first part, we learned that a module was a namespace, a way to regroup similar things to help us organize our application better and to avoid name clashes. It was rather easy to understand because we didn’t speak about the true power that resides in modules.

Other than a namespace, what is a module?

A module is like a class with 3 key differences :

  1. It is not a class (… DUH!)
  2. It cannot be instantiated (i.e. you cannot do x = MyModule.new)
  3. It can be mixed in a class to enhance its possibilities

And here is the tricky part : Although a module cannot have instances, it can still have instance methods. How is it possible? Well, you guessed it : those instance methods will become the instance methods of the client (the class).

That is what we call a mixin!

Mixins, quite a funny word don’t you think? No, you’re absolutely right, it is not funny at all. Mixin just means Mixed in, as in : This module has been mixed in my class, let’s play Twister!

When you decide to mix a module in one of your class, the latter automatically gains some new functionalities… for free! In a sense, it’s a little bit like class inheritance, at the exception of these 2 points :

  1. There is no hierarchy : the class isn’t the child of the module, it just includes it. You just have to see the mixed-in module as a set of additional methods for your class.
  2. You can include more than one module in a class, thus creating the effect of multiple inheritance… which is something most languages simply don’t allow

A little example to illustrate my first point :

Class inheritance : An aloes (class) IS A plant (class)
Mixins : An aloes (class) HAS some healing properties (module)

If we take for granted that our module “HealingProperties” is general enough in its implementation to fit many purposes, we could very well mix it in any other class that needs healing properties. (a drug, Wolverine, Kenny in South Park, etc). This is how we would do it :

The Comparable module

The built-in module called Comparable is possibly one of the best example to use to understand the usefulness of modules because it contains general purpose methods that can interest different kind of classes.

Comparable contains the following methods (yes, these are all methods, not operators) :

<, <=, ==, >, >=, between?

What are those methods doing exactly? Well, they compare sortable things together. However, those “things” to compare have to be in the class that includes the module, not in the module itself. How can the module knows what the “client” class is all about? The answer lies in the secret treaty that exists between Comparable and any class that wants to use it. The class has to specify, by implementing the <=> method, the attribute on which the comparison must operate. Note that <=> is a comparison method that is always expected to return +1 if the receiver is higher than the method argument, -1 if the method argument is higher then the receiver and 0 if both the receiver and the method argument are equal. In case you’re confused, if I write x <=> y, x is the receiver and y is the method argument.

In this example, I told Comparable that the comparison had to operate on the iq attribute. Doing so, my Dog class gained access to 6 comparison methods without me having to write a single line of code.

A little clarification about <=>

This hasn’t much to do with mixins, but it may be confusing at first : Why do we used <=> once more in the implementation of our <=> method? Wouldn’t it create some kind of infinite loop? No… because when we do self.iq <=> other.iq, we call the <=> method that resides in the Fixnum class (since iq is a fixnum). The <=> implementation in the Fixnum class already returns -1, 0 or +1 based on which one of the 2 fixnums is the highest. If iq would have been something else that DOESN’T implement the <=> method, we would have been forced to implement the <=> ourselves (e.g. return 0 if this_condition; return -1 if this_other_condition; return 1 if yet_another_condition)

It’s modules like Comparable and Enumerable that makes the concept of modules so attracting. Yes, modules can be used as namespaces only, but they really shine when you use them to enhance your classes. They become especially powerful when they are consisted of general purpose methods and when they only require a small piece of information from the class to work properly.

  • http://www.danielfischer.com Daniel Fischer

    Hey, that was wonderful! Thank you :)

  • BK

    So if I understand this correctly, it’s almost like a “preimplemented” interface… Interesting! Finally a plus for Ruby over dotnet! ;)

  • http://www.rubyfleebie.com Frank

    @BK,

    Exactly. I find the term “preimplemented” interface pretty accurate in fact! Thanks

  • Vivek Dandage

    Hey, really cool. Thank you. :)

  • jonny_noog

    “Finally a plus for Ruby over dotnet!”

    …Finally?

  • Pingback: How to display a collection grouped by an attribute value in Rails()

  • wdj

    Alas….I understand Ruby Modules …Thanks

  • Pancho

    Thanks so much for such a clear and understandable explanation!

  • http://twitter.com/fr33night freenight

    thanks Frank, got it. but what’s about the ‘instance variables’ in module??

  • freenight

    wow … that’s not my avatar..

  • http://www.rubyfleebie.com Frank

    Thanks guys, I’m glad you liked the post!

    freenight,this is a very good question.

    Instance variables in modules can belong to either :

    1: The module
    2: The client class

    If you need a variable that will exist at “module level” you will do it this way

    module SomeModule
    def self.set_instance_variable
    #this method is not accessible for a client class
    #in this case the term “instance” refers to the module itself
    @x = “bla bla bla”
    end

    def self.get_instance_variable
    @x
    end
    end

    SomeModule.set_instance_variable
    SomeModule.get_instance_variable #output : bla bla bla

    Conclusion : When you use instance variables inside “module level” methods, these variables are only available in the module itself.

    Now, if you want to use instance variables where an “instance” refers to the client class instance and NOT the module itself, you have to proceed this way.

    module SomeModule
    def set_instance_variable
    #only difference is that I removed the ‘self.’ part in the method definition. It means that this
    #method will reside into the client class instance and NOT in the module itself
    @x = “bla bla bla”
    end

    def get_instance_variable
    @x
    end
    end

    class SomeClass
    include SomeModule
    end

    x=SomeClass.new

    x.set_instance_variable
    x.get_instance_variable #output is “bla bla bla”

  • freenight

    got it Frank.

    the first form:

    module SomeModule
    def self.talk
    @x = ..

    since module themselves are object, classes that get this module included have no access to it’s instance method, thus this @x is visible only in the module itself.

    on the other hand, instance methods defined in modules becomes instance methods of object with which the class has got the module mixed in, thus this instance variable is.. well instance variable in
    per-object basis,right Frank??

    sorry for my pool english..

  • http://www.rubyfleebie.com Frank

    freenight, Exactly.

    I’ll try to sum it up in a more concise way :

    When you are in a module and define a “module method” (e.g. def self.my_module_method), the execution context is the module itself (which is an object as well). When you are in a module and define an “instance method” (e.g. def my_instance_method), the execution context is the class instance that includes the module. This is like you had pasted all the instance methods from the module in your class. This is why we can say that the instance variables are in the class

  • priya

    wow ,wonderful explanation of module and mixin . i enjoyed reading it. i learnt d concept very easily by your explanation.

  • rodnic

    Congrats! Great article. I really enjoyed this blog. Bookmarked!

  • Pingback: Ruby Modules Explained | Jim McKerchar()

  • Arild Shirazi

    Actually, not quite correct… including a module inserts that module in the class inheritance hierarchy:

    module M; end
    class Fixnum; include M; end
    2.class.ancestors
    => [Fixnum, M, Integer, Precision, Numeric, Comparable, Object, Kernel]

    Knowing this better explains why you get the methods of a mixin, but no direct access to it’s instance variables.

  • http://www.luigi7up.com Luka

    I am new to Ruby, but not that new to reading tech. posts. This one is funny and really concise! thanks ;)

  • http://vischeck.com/vischeck/vischeckUrl=.php?origUrl=http://username24832wxa.wordpress.com webcasting services

    Great site. A lot of useful information here. I am sending it to some friends ans also sharing
    in delicious. And obviously, thank you in your effort!

  • http://bestcribs2014.com bestcribs2014.com

    Hello, i think that i noticed you visited my site
    so i came to go back the prefer?.I am attempting to in finding issues to improve my website!I suppose its ok to make
    use of a few of your concepts!!

  • http://vscchyxsmm49669.mywapblog.com/ lead marketing

    Can you tell us more about this? I’d want to
    find out some additional information.

  • http://mailingsoftware1366492.wordpress.com/author/mailingsoftware1366492/ webcasts

    Aw, this was a very nice post. Taking the time and actual effort to create a great article… but what can I
    say… I hesitate a lot and never manage to get nearly
    anything done.

  • jo

    I was going nuts trying to figure out what Comparable methods do and how to code/implement them. After reading through countless books and online sources, this blog post is the only one that explained it in terms that a complete beginner like me would understand. Thanks so much for this very informative and valuable post on the comparable module.