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:

StackOverflow post

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.