Extend vs Include
This is a follow up to my July 27th post. I’m going to try to make this a short, concise blog post. The closer this is to a Stack Overflow answer, the more likely I am to re-read this post as a reference.
include: mixin a module’s methods into a class’s instances. If a module contains a class method called “included”, it is called after inclusion. Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module AModule
def self.included(base)
puts "included #{self} into #{base}"
end
def speak
puts "I am #{self}"
end
end
# => nil
class AClass
include AModule
end
# included AModule into AClass
# => AClass
AClass.speak
# NoMethodError: undefined method `speak' for AClass:Class
an_instance = AClass.new
# => #<AClass:0x007fcdd487b8e8>
an_instance.speak
# I am #<AClass:0x007fcdd487b8e8>
# => nil
extend: mixin a module’s methods into a class’s, making the module methods class-methods. A similar callback capability is built in by defining a class method on the module extended. If defined, it’ll be called after the
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module BModule
def self.extended(base)
puts "extended #{self} into #{base}"
end
def speak
puts "I am #{self}"
end
end
class BClass
extend BModule
end
# extended BModule into BClass
# => BClass
BClass.speak
# I am BClass
# => nil
I was careful to write “mixin” for my two definitions above, as monkeypatches to AModule and BModule will be seen in classes that included or extended their behavior.
Example: (continuing from the code block above)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# yarr we're monkey patching
module AModule
def speak
puts "there be monkeys"
end
end
an_instance.speak
# there be monkies
# => nil
# Let's see how monkey patching affects extend
module BModule
def speak
puts "there B monkeys"
end
end
# => nil
BClass.speak
# there B monkeys
# => nil
I spent the extra time to explore whether code from modules is copied into their respective classes because I said this during the interview I described in my July 27th blog post. One of my interviewers corrected me, and he seems to indeed be right. At least I’m learning from looking like an ass.
Additional references:
Yehuda Katz post on include and exclude idioms, calling for a style change
Last note about extend: extend can be used on singleton objects, but I don’t see a use case for this. I suppose it’s something to keep an eye out for.