Friday, May 2, 2008

Include vs Extend

A common cause of confusion in Ruby is discerning the difference between Module#include and Object#extend and when to use one over the other.

A few examples will help us understand. Lets create a file example.rb

cd module Coolness
def cool_method
puts "This is one cool method!"
end
end

class A
include Coolness
end

a = A.new
a.cool_method


Then we run it

$ ruby example.rb
This is one cool method!


When you include a module from another module (remember all classes are modules) you are in essence adding in all of the included module's constants, methods, and module variables to the module that is including it. It's a mouthful, I know. So all of the methods of the module are available as instance methods. Now lets see what happens when we modify our file and use extend instead.

class A
extend Coolness
end

a = A.new
a.cool_method


$ ruby example.rb
example.rb:14: undefined method `cool_method' for # (NoMethodError)


When you use extend you are adding the modules methods to the instance from which it is called on. In our case we are extending the module from the singelton class A so all the modules methods are available on the singelton class A, not on the instances of class A. I know, its another mouthful. So when you use extend in this way you are in essence adding the modules methods as class methods, not instance methods. So to execute cool_method we must call it as a method the class A itself.

class A
extend Coolness
end

A.cool_method


$ ruby example.rb
This is one cool method!


If we wanted cool_method to be available to an instance of class A we need to explicitly extend the instance.

class A
extend Coolness
end

a = A.new
a.extend(Coolness)
a.cool_method


$ ruby example.rb
This is one cool method!


So to summarize if you wanted to add instance methods to a class you should use include. If you want to add class methods to a class you should use extend. And finally, if you want to add instance methods to one particular instance of a class you should use extend on the instance itself.

Let me know if you have any questions.

No comments: