Sep 09, 2007 @ 11:27 pm

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 (this one is the killer)
  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 :

module HealingProperties
  def heal_wounds
    #do something that heal wounds
  end
end

class Wolverine
  include HealingProperties
  def kill_something_with_my_claws!
    #Arrr!
  end
end

logan = Wolverine.new
logan.kill_something_with_my_claws!
logan.heal_wounds

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.

class Dog
  include Comparable
  attr_accessor :iq
  def initialize(iq)
    self.iq = iq
  end

  #Honoring the contract with Comparable...
  def <=>(other)
    self.iq <=> other.iq
  end
end

spike = Dog.new(60)
rex = Dog.new(40)
retard = Dog.new(30)
dumbass = Dog.new(20)
dumber = Dog.new(15)
bozo = Dog.new(10)

puts "Make fun of dumbass" if spike > dumbass
puts "Make fun of dumbass even more" if dumbass <= rex
puts "Realize in shame that dumbass is not a dog but an African violet" if dumbass < bozo

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.

Bookmark this post : These icons link to social bookmarking sites where readers can share and discover new web pages.
  • DZone
  • Reddit
  • del.icio.us
  • Digg
  • Furl
  • Technorati
  • StumbleUpon
Posted under : In depth
17 Comments

Hey, that was wonderful! Thank you :)

Comment by : Daniel FischerNo Gravatar
— September 10, 2007 @ 2:11 pm

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

Comment by : BKNo Gravatar
— September 18, 2007 @ 9:24 am

@BK,

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

Comment by : FrankNo Gravatar
— October 29, 2007 @ 2:54 pm

Hey, really cool. Thank you. :)

Comment by : Vivek DandageNo Gravatar
— July 16, 2008 @ 5:14 am

“Finally a plus for Ruby over dotnet!”

…Finally?

Comment by : jonny_noogNo Gravatar
— July 24, 2008 @ 3:00 am

[...] is a job for Enumerable#group_by (Enumerable is a module that is mixed in the Array [...]


Alas….I understand Ruby Modules …Thanks

Comment by : wdjNo Gravatar
— July 21, 2009 @ 9:58 am

Thanks so much for such a clear and understandable explanation!

Comment by : PanchoNo Gravatar
— November 24, 2009 @ 1:42 am

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

Comment by : freenightNo Gravatar
— November 24, 2009 @ 3:31 am

wow … that’s not my avatar..

Comment by : freenightNo Gravatar
— November 24, 2009 @ 3:32 am

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”

Comment by : FrankNo Gravatar
— November 27, 2009 @ 11:53 am

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

Comment by : freenightNo Gravatar
— November 28, 2009 @ 1:16 am

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

Comment by : FrankNo Gravatar
— November 28, 2009 @ 9:52 am

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

Comment by : priyaNo Gravatar
— June 8, 2010 @ 11:56 pm

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

Comment by : rodnicNo Gravatar
— July 2, 2010 @ 6:33 pm

[...] An Introduction to Modules: Part 2 [...]

— November 5, 2010 @ 12:58 pm

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.

Comment by : Arild ShiraziNo Gravatar
— January 24, 2011 @ 3:47 pm




Leave a comment
Name (required)
Email (will not be publish) (required)
Website