All Rubyists should be familiar with the common definitions for
include a module to add instance methods to a class and
extend to add class methods.
Unfortunately, this common definition isn’t entirely accurate.
It fails to explain why we use
instance.extend(Module) to add methods to an instance.
Shouldn’t it be
To figure this out we’re going to start by discussing where methods are stored.
The methods I’m storing for you and the guy holding mine.
Objects in Ruby do not store their own methods. Instead, they create a singleton class to hold onto their methods.
class A def self.who_am_i puts self end def speak_up(input) puts input.upcase end end
The interpreter will create an
A class and a singleton class to attach to it (we’ll refer to the singleton class of an object by prepending
' to the object name).
Any instance methods (i.e.
speak_up) are added to the methods stored on
The class methods (i.e.
who_am_i) are stored on
> A.singleton_methods # methods on 'A # => [:who_am_i]
This same process happens with instance objects.
If we have an instance of
A and we add a method to it we can’t store it on the instance.
Remember, objects in Ruby do not store their own methods.
a = A.new def a.not_so_loud(input) puts input.downcase end
Once again we create a singleton class for
a to store the
Now we have a method that only belongs to
a and does not affect other instances of
I’m my own father?
A class holds the methods and knows the inheritance chain needed for
a and all other instances of
Similarly the singleton class,
'A, holds the methods and knows the inheritance chain for
You can think of
A as an instance of
The catch is that we don’t talk directly to
This means we need some way to distinguish between adding methods to
extend come in.
include a module in an object, you’re adding the methods into the inheritance chain that the object is tracking.
class A include M end
We can see that this is the case by checking
> A.ancestors # => [A, M, Object, Kernel, BasicObject]
extend is the same as doing an
include on the object’s singleton class.
class A extend M end
Once again we can confirm this by checking
> A.singleton_class.ancestors # => [M, Class, Module, Object, Kernel, BasicObject]
We can also call
extend on an instance.
a = A.new a.extend(M) > a.singleton_class.ancestors # => [M, A, Object, Kernel, BasicObject]
If you think of
extend as a way to add class methods then what we just did doesn’t make much sense.
Once you reframe it as adding methods to the singleton of an object the picture above becomes more clear.
Any time you call
include it will check the module to see if there is a method named
This method is executed when the module is included.
It’s like an
initialize for includes.
As you might suspect,
extend has its own version of this called
When you want to add both instance and class methods you can do so using the included hook.
module M def self.included(base) base.extend(ClassMethods) end def speak_up(input) puts input.upcase end module ClassMethods def who_am_i puts self end end end class C include M end c = C.new
This works by first including
C’s inheritance chain.
C which adds the methods to
'C’s inheritance chain.
When you start to dig past the common uses
extend can seem odd and intimidating.
Once you understand the underlying implementation it all starts to make better sense.
extend once more.
include: adds methods from the provided Module to the object
include on the singleton class of the object
If you want a more details about what the interpreter is doing I recommend watching Patrick Farley’s talk on Ruby Internals.