Module and Mixin revisited

From the feedback I got from ruby on rails course, there seem to be many students who find many core concept of ruby difficult to understand. So, the course mailing thread aside, I’ll try my best to explain some of these concept in depth here. This post will be about the concept of Mixin and ruby Module.

Mixin and Module

Wikipedia offers one of the best description of what mixin is.

In OO languages, a mixin is a  class that provides a certain functionality to be inherited by a subclass, but is not meant to stand alone. Inheriting from a mixin is not a form of specialization but is rather a means to collect functionality. A class may inherit most or all of its functionality by inheriting from one or more mixins through multiple inheritance.” - Wikipedia

Ruby’s flavor of mixin comes in the form of Module. Module is a collection of methods and constant. The most commonly use of module is to have its members (methods, features) “mixed” into a class. The most evident example is the Kernel methods that are mixed-in to Object class. Because of this, methods from Kernels are universally available to all ruby objects.

Basic example

In the last post, I showed an example of ‘puts’ method. ‘puts’ is available to all Object in Ruby. ‘puts’ exists in Kernel module, and Kernel is mixed into Object class. Now since everything in ruby is an Object, they also automatically have access to ‘puts’ in Kernel module.

puts "string".class.ancestors
# [String,Enumerable,Comparable,Object,Kernel]

puts Object.class.ancestors
# [Class,Module,Object,Kernel]

puts Object.private_methods.include?('puts')
# true => Object has 'puts' method as member

puts Object.class.private_methods(false).include?('puts')
# false => 'puts' is inherited member

puts Kernel.class.private_methods.include?('puts')
# true => 'puts' is a member of Kernel module

Another example is the use of Math module. you can access Math’s constant value without having to include Math module

puts Math::PI
# 3.141592653589793

puts Math.sqrt(256)
# 16

Matz has called the mix-in feature of module “single inheritance with implementation sharing“. It’s a way of getting benefit of multiple inheritance without the mess and difficulties.

Module instance method

With “include” keyword, the modules methods become available  as object’s instance methods. You can think of including Ruby module to a class is similar to appending functions of that module to an object.

module MyModule
   def instance_method
      puts 'this is MyModule instance_method'
   end
end
class MyClass
   include MyModule
end
my_class = MyClass.new
my_class.instance_method #this is MyModule instance_method

As you can see, with ‘include‘ keyword, MyModule’s method becomes available to all instance of MyClass object.

Module class method with append_features

It’s also possible to make module methods available to class. What we’re going to use is ‘append_features‘. By overriding module’s ‘append_features' method with class as parameter, nested method under append_features will be accessible to that class.

module MyModule
   def MyModule.append_features(childClass)
      def childClass.classMethod
         puts 'MyModule classMethod'
      end
      super #HAVE to call super here
   end
 
   def instance_method
      puts 'this is MyModule instance_method'
   end
end
my_class = MyClass.new
my_class.classMethod     # illegal
MyClass.classMethod      # print MyModule classMethod

A few things to note here. First,’append_features‘ actually do the work equivalent to include operation. Therefore, we need to call super. Otherwise, the rest of the code in the module wouldn’t be included at all. Another thing, the nested method can only be singleton/static method.

Module class method with inheritance

Alternative to using append_features, you can mix in module’s instance methods as class methods with inheritance

class MyOtherClass
   class << self
      include MyModule
   end
end
MyOtherClass.instance_method
# print this is MyModule instance_method
# instance_method becomes class method

As you can see, the ruby language itself is very powerful. But by nature, it still follows the Object Oriented principle. On the future post, I’ll review the concept of blocks and lambda expression.

Teera on July 29th 2008 in Software Development, Ruby

2 Responses to “Module and Mixin revisited”

  1. Marc responded on 22 Oct 2008 at 6:29 am #

    Thanks for the explanation!

  2. TEERA 2.0 » Module and Mixin revisited (ruby) | Marc's blog responded on 29 Oct 2008 at 6:17 am #

    […] TEERA 2.0 » Module and Mixin revisited (ruby) […]

Trackback URI | Comments RSS

Leave a Reply