Difference Between Include and Extend in Ruby

What is the difference between include and extend in Ruby?

What you have said is correct. However, there is more to it than that.

If you have a class Klazz and module Mod, including Mod in Klazz gives instances of Klazz access to Mod's methods. Or you can extend Klazz with Mod giving the class Klazz access to Mod's methods. But you can also extend an arbitrary object with o.extend Mod. In this case the individual object gets Mod's methods even though all other objects with the same class as o do not.

What is the difference between include module and extend module in Ruby?

I wrote a blog posting about this a long time ago here.

When you're "including" a module, the module is included as if the methods were defined at the class that's including them, you could say that it's copying the methods to the including class.

When you're "extending" a module, you're saying "add the methods of this module to this specific instance". When you're inside a class definition and say "extend" the "instance" is the class object itself, but you could also do something like this (as in my blog post above):

module MyModule
def foo
puts "foo called"
end
end

class A
end

object = A.new
object.extend MyModule

object.foo #prints "foo called"

So, it's not exactly a class method, but a method to the "instance" which you called "extend". As you're doing it inside a class definition and the instance in there is the class itself, it "looks like" a class method.

Extend and Include

module Foo
def self.included(base)
base.extend Foo::ClassMethods
end

module ClassMethods
def guitar
"gently weeps"
end
end
end

class Bar
include Foo
end

puts Bar.guitar

What is the difference between include and require in Ruby?

What's the difference between
"include" and "require" in Ruby?

Answer:

The include and require methods do
very different things.

The require method does what include
does in most other programming
languages: run another file. It also
tracks what you've required in the
past and won't require the same file
twice. To run another file without
this added functionality, you can use
the load method.

The include method takes all the
methods from another module and
includes them into the current module.
This is a language-level thing as
opposed to a file-level thing as with
require. The include method is the
primary way to "extend" classes with
other modules (usually referred to as
mix-ins). For example, if your class
defines the method "each", you can
include the mixin module Enumerable
and it can act as a collection. This
can be confusing as the include verb
is used very differently in other
languages.

Source

So if you just want to use a module, rather than extend it or do a mix-in, then you'll want to use require.

Oddly enough, Ruby's require is analogous to C's include, while Ruby's include is almost nothing like C's include.

Ruby mixins: extend and include

The difference is that include will add the included class to the ancestors of the including class, whereas extend will add the extended class to the ancestors of the extending classes' singleton class. Phew. Let's first observe what happens:

Bacon.ancestors
#=> [Bacon, Object, Kernel, BasicObject]

Bacon.singleton_class.ancestors
#=> [Bar, Baz, Class, Module, Object, Kernel, BasicObject]

Bacon.new.singleton_class.ancestors
#=> [Bacon, Object, Kernel, BasicObject]

Bacon.is_a? Bar
#=> true

Bacon.new.is_a? Bar
#=> false

And for the Egg class

Egg.ancestors
#=> [Egg, Bar, Baz, Object, Kernel, BasicObject]

Egg.singleton_class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]

Egg.new.singleton_class.ancestors
#=> [Egg, Bar, Baz, Object, Kernel, BasicObject]

Egg.is_a? Bar
#=> false

Egg.new.is_a? Bar
#=> true

So what foo.is_a? Klass actually does is to check whether foo.singleton_class.ancestors contains Klass. The other thing happening is that all the ancestors of a class become ancestors of an instances' singleton class when the instance is created. So this will evaluate to true for all newly created instances of any class:

Egg.ancestors == Egg.new.singleton_class.ancestors

So what does all this mean? extend and include do the same thing on different levels, i hope the following example makes this clear as both ways to extend a class are essentially equivalent:

module A
def foobar
puts 'foobar'
end
end

class B
extend A
end

class C
class << self
include A
end
end

B.singleton_class.ancestors == C.singleton_class.ancestors
#=> true

where class << self is just the odd syntax to get to the singleton class. So extend really just is a shorthand for include in the singleton class.

include vs. extend and Comparable module in Ruby

Include is for adding methods to an instance of a class and extend is for adding class methods:
http://www.railstips.org/blog/archives/2009/05/15/include-vs-extend-in-ruby/

Both :> and :between are methods.
The difference is here:

If you see Class0 methods you have :>, :>=, :<, :<= defined as class methods.
When Class2 extend Comparable it will get the between? method as class method.

In the second case you have Class0 and Class1 instances, so the a instance of Class0 doesn't have the :>, :>=, :<, :<=, :between? methods defined as instance methods. Once you include the comparable Module in Class1, it will get all this methods as instance methods from Module, so you will have all [:>, :>=, :<, :<=, :between?] methods available in the instance b.

This is why you get those results.

I found another nice explanation of include VS extend here:
http://aaronlasseigne.com/2012/01/17/explaining-include-and-extend/

ActiveSupport::Concern should be included or extended

You need to extend the module with ActiveSupport::Concern in order for the ActiveSupport::Concern#included and #class_methods methods to work properly.

These two methods are after all pretty much the only reason for its existance.

module A
extend ActiveSupport::Concern
# raises ArgumentError (wrong number of arguments (given 0, expected 1))
included do
puts "Hello World"
end
end

module B
extend ActiveSupport::Concern
included do
puts "Hello World"
end
end

class C
include B
end
# Outputs Hello World

Check out what happens if we inspect the included method:

module AB
include ActiveSupport::Concern
puts method(:included).source_location # nil
end
module ABC
extend ActiveSupport::Concern
puts method(:included).source_location # .../ruby/gems/2.7.0/gems/activesupport-6.0.2.1/lib/active_support/concern.rb
end

When we extend the module with ActiveSupport::Concern we are putting it on the ancestors chain of ABC, thus the methods of ActiveSupport::Concern are available as module methods of ABC. This does not happen when you use include and the included method called is actually Module#included from the Ruby core.

Ruby extend & include tracing code

When you extend a module, the methods in that module become "class methods"**. So, when you extend Inventoryable, create becomes available as a method on the Shirt class.

When you include a module, the methods in that module become "instance methods"**. So, when you include Inventoryable, create is not available on the Shirt class (but is available on an instance of Shirt).

To make create available on the Shirt class when using include, you can use the included hook. That might look something like:

module Inventoryable
module ClassMethods

def create
puts "create!"
end

end

module InstanceMethods

end

def self.included(receiver)
receiver.extend ClassMethods
receiver.include InstanceMethods
end
end

Then if you do:

class Shirt
include Invetoryable
end

You can do:

> Shirt.create
create!
=> nil

** The ruby purists in the crowd will correctly point out that, in ruby, everything is an instance method and that there are no class methods. That is formally 100% correct, but we'll use the colloquial meaning of class and instance methods here.



Related Topics



Leave a reply



Submit