include and extend

April 6th, 2008

include and extend are commonly used to add methods to Ruby classes, and sometimes, why we use one or the other is not clear. Both do similar operations, but they are not equivalent. extend is more parsimonious adding only methods, includealso includes constants and module variables.

A simple guideline is to include instance methods and to extend class methods.

Here is an example of a class with an instance method and a class method. We have reopened the class so that we can show the differences from the original empty class:

def list_diff(label, list1, list2)
  puts "#{label}: #{(list1 - list2).sort.join ' '}"
end

class One
end

methods_from_new = One.new.methods
methods_from_class = One.methods

class One
  def instance_method
  end

  def One.class_method
  end
end

list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class

when run shows the expected differences:

Instance One.new diff: instance_method
Class One diff: class_method

Now lets create and include a module:

module ModuleTwo
  CONSTANT_TWO = "two"
  def module_method
  end
end

class One
  include ModuleTwo
end

list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class
puts "has constant? #{One.constants.sort.join ' '}"

when run shows that module_method and CONSTANT_TWO are now available:

Instance One.new diff: instance_method module_method
Class One diff: class_method
has constant? CONSTANT_TWO

And if we extend another module:

module ModuleThree
  CONSTANT_THREE = 'three'
  def another_module_method
  end
end

class One
  extend ModuleThree
end

list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class
puts "has constant? #{One.constants.sort.join ' '}"

When run, shows that another_module_method is now available as a class method, but CONSTANT_THREE is not1:

Instance One.new diff: instance_method module_method
Class One diff: another_module_method class_method
has constant? CONSTANT_TWO

Finally, we can use include instead of extend to include class methods:

module ModuleFour
  CONSTANT_FOUR = 'four'
  def yet_another_module_method
  end
end

class One
  class << self
    include ModuleFour
  end
end

list_diff "Instance One.new diff", One.new.methods, methods_from_new
list_diff "Class One diff", One.methods, methods_from_class
puts "has constant? #{One.constants.sort.join ' '}"
When run, shows that yet_another_module_method is available as a class method, but CONSTANT_FOUR is not2
Instance One.new diff: instance_method module_method
Class One diff: another_module_method class_method yet_another_module_method
has constant? CONSTANT_TWO

1 Remember, include does more3 than extend.

2 For more details, check Programming Ruby: The Pragmatic Programmer’s Guide .

3 Bonus!

module ModuleFive
  CONSTANT_FIVE = 'five'
  def module_five
  end
end

one = One.new
one.extend ModuleFive

list_diff "Instance extends module", one.methods, methods_from_new
puts "has constant? #{one.class.constants.sort.join ' '}"

Instance extends module: instance_method module_five module_method
has constant? CONSTANT_TWO

Leave a Reply