Skip to main content

The difference between include and extend in Ruby module

In Ruby, both include and extend are used to incorporate modules into classes, but they serve different purposes and are used in different contexts. Understanding the difference between these two methods is crucial for effectively organizing and utilizing code in Ruby applications.

Here’s a detailed explanation of the differences between include and extend:

include

  • Purpose: include is used to add the module’s instance methods to the target class.
  • Usage: When you include a module in a class, the module’s methods become instance methods of the class.
  • Scope: Affects instances of the class. Any object created from the class will have access to the module’s methods.
  • Inheritance: If a subclass is created from the parent class that included the module, the subclass will also have access to the module’s methods.

Example

1
2
3
4
5
6
7
8
9
10
11
12
module Greetings
  def hello
    "Hello!"
  end
end

class Person
  include Greetings
end

person = Person.new
puts person.hello  # Output: "Hello!"

In this example, the hello method from the Greetings module is available as an instance method of the Person class. Any instance of Person can call hello.

extend

  • Purpose: extend is used to add the module’s methods as class methods to the target object.
  • Usage: When you extend a module in a class (or on an object), the module’s methods become class methods.
  • Scope: Affects the class itself or the object it’s called on. The methods become part of the object’s singleton class.
  • Inheritance: Extending a module does not make the module’s methods available to instances of the class, only to the class itself or to the extended object.

Example

1
2
3
4
5
6
7
8
9
10
11
module Greetings
  def hello
    "Hello!"
  end
end

class Person
  extend Greetings
end

puts Person.hello  # Output: "Hello!"

In this example, the hello method from the Greetings module is available as a class method of the Person class. The Person class itself can call hello, but instances of Person cannot.

Key Differences

Feature include extend
Scope Instance-level: adds instance methods Class-level: adds class methods
Usage Mixes in methods to be available for instances Adds methods to the class or object itself
Inheritance Methods are available to subclass instances Methods are not inherited by subclass instances
Purpose Share behaviors across instances of multiple classes Enhance the class or object with additional methods

When to Use include vs. extend

  • Use include when you want to share common behaviors among instances of different classes. It’s ideal for adding functionality to instances.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    module Loggable
      def log(message)
        puts "[LOG] #{message}"
      end
    end
    
    class User
      include Loggable
    end
    
    user = User.new
    user.log("This is a log message.")  # Output: "[LOG] This is a log message."
    
  • Use extend when you want to enhance a class or a specific object with additional methods, typically for utility or class-level functionality.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    module ClassLogger
      def log_class_activity
        puts "Class activity logged."
      end
    end
    
    class User
      extend ClassLogger
    end
    
    User.log_class_activity  # Output: "Class activity logged."
    

Combining include and extend

Sometimes, you might want to use both include and extend to provide both instance and class methods. You can do this by defining the instance methods directly in the module and using a nested module for class methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module Greetings
  def hello
    "Hello from instance!"
  end

  module ClassMethods
    def hello
      "Hello from class!"
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Person
  include Greetings
end

person = Person.new
puts person.hello        # Output: "Hello from instance!"
puts Person.hello        # Output: "Hello from class!"