Home > OS >  Ruby: Are these two methods of mixing-in module methods equivalent?
Ruby: Are these two methods of mixing-in module methods equivalent?

Time:01-26

I have a module and a class.

module Dog
  def speak
    "woof"
  end
end

class Daschund; end

I create two separate instances of the class.

sausage = Daschund.new
saveloy = Daschund.new

If I want to add Dog#woof as an instance method of my two new objects, I can do it in two ways:

class << sausage
  include Dog
end
> sausage.speak
=> "woof"
saveloy.extend Dog
> saveloy.speak
=> "woof"

Are the two methods equivalent? I know the first adds the module's method to the object's meta-class. Does object#extend do the same thing? Or is it doing something slightly different? Is there any way to prove this?

CodePudding user response:

According to the docs for Object, extending an object with a module means including that module to the object's singleton class:

extend: Includes the given modules in the singleton class of self.

Inspecting the ancestors of both objects' singleton classes confirms this:

sausage.singleton_class.ancestors
#=> [#<Class:#<Daschund:0x00007fa6af92e868>>, Dog, Daschund, Object, Kernel, BasicObject]

saveloy.singleton_class.ancestors
#=> [#<Class:#<Daschund:0x00007fa6af92e778>>, Dog, Daschund, Object, Kernel, BasicObject]

The actual implementation details of course depend on the Ruby implementation and version you are using. For MRI/YARV, you have rb_extend_object defined as:

void
rb_extend_object(VALUE obj, VALUE module)
{
    rb_include_module(rb_singleton_class(obj), module);
}
  •  Tags:  
  • ruby
  • Related