Translator's note: before reading this post, I recommend that you first familiarize yourself with the post. Understand the Ruby metaclasses .All rubists are familiar with the formal definitions for
include and
extend . You do
include a module to add class instance methods, and
extend - to add class methods. Unfortunately, these definitions are not entirely accurate. They cannot explain why we use
instance. extend (Module) to add methods to the object. Shouldn't we in this case use an
instance. include (Module) ? To understand this question, let's start by finding out where the methods are stored.
The methods I keep for you and the guy who keeps my methods
Objects in Ruby do not store their own methods. Instead, they create a singleton class so that it stores 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 a class
A and a singleton class attached to it (we will refer to the object's singleton class using the prefix
' in front of the object name). Any class instance methods (like
speak_up ) are added to methods stored in class
A. Class methods (like
who_am_i ) are stored in class
' A. A.singleton_methods

The same thing happens with instances of a class. If we have an object of class
A and we add a method to it, we cannot store this method inside the object itself. Remember - objects in Ruby do not store their own methods.
a = A.new def a.not_so_loud(input) puts input.downcase end
Here again, a singleton class is created for the object "
a ", so that it
stores the not_so_loud method.

Now we have a method that belongs only to the object "
a " and does not affect other objects of class
A.Am I my father?
Class
A contains methods and information about the chain of inheritance needed for object "
a " and all other objects of class
A. Similarly, the singleton class
A contains methods and information about the inheritance chain for class
A. You can think of class
A as an object of class
' A. The trick is that we cannot directly refer to the singleton class
' A. This means that we need to somehow distinguish between adding methods to
A and to
'A. Here then
include and
extend and come into play.
include
When you
include a module in an object, you add methods to the object's inheritance chain.
class A include M end

This is easily verified by checking the ancestors of class
A. A.ancestors
extend
extend is the same as
include , but for a singleton object class.
class A extend M end

And again we can confirm this by checking the ancestors of the class
' A. A.singleton_class.ancestors
We can also use
extend for an object.
a = A.new a.extend(M) a.singleton_class.ancestors

If you think about
extend as a way to simply add class methods, then everything we have just done does not make much sense. However, if you look at it as a way to add methods to the singleton class of an object, then the examples above will become clearer.
Hook included
Each
include call checks the plug-in for the method
included . This method is executed when the module is connected using
include . This is like a constructor (
initialize ) for connections. As you may have guessed,
extend for this purpose has its own method -
extended . So when you want to add both class methods and class instance methods at once, you can use the
included hook for this.
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
First we include the module
M in the inheritance chain of class
C.
Then we extend class
C by adding methods to the inheritance chain of the class
' C.
Conclusion
When you start digging deeper than the typical use of
include and
extend , you find something strange and frightening. However, it is necessary to understand the underlying implementation and everything at once makes sense. Let's now give the definition of
include and
extend again.
include - adds module methods to the object.
extend - calls the
include for the singleton class of the object.
If you are interested in even more details about how the interpreter works, then I recommend watching
Patrick Farley’s presentation
on Ruby Internals .
Translator's note: Another thing, why we cannot use instance.include (Module) is that the include method is a private method of the Module class. In general, before reading this article, I also did not imagine the work of extend and include , so I considered it worthwhile to translate it.
I will bring some more clarity: what is called the “singleton class” (singleton class) in the article has other names: metaclass and eigenclass. This is all the same entity for which there is no “official" name in the Ruby community yet. I used the "singleton class" because it's closer to the original. However, Matz (the creator of the language) is more impressed with the term eigenclass.