Object#extend inner workings

I've got a question regarding the inner workings of extend. Consider the following code that uses Object#extend twice:

class Klass
  def hello(options = {})
    p options
  end
end

module Mod1
  def hello(options = {})
    super(options.merge({:mod1 => true}))
  end
end

module Mod2
  def hello(options = {})
    super(options.merge({:mod2 => true}))
  end
end

k = Klass.new
k.hello #=> {}

k.extend(Mod1)
k.hello #=> {:mod1=>true}

k.extend(Mod2)
k.hello #=> {:mod2=>true, :mod1=>true}

I was a bit surprised that the second extend didn't clobber the first. How is this handled by the Ruby interpreter? Is it creating more than one eigenclass?

Tom

···

--
Tom Werner
Helmets to Hardhats
Software Developer
tom@helmetstohardhats.org
www.helmetstohardhats.org

Tom Werner wrote:

I've got a question regarding the inner workings of extend. Consider the following code that uses Object#extend twice:

class Klass
def hello(options = {})
   p options
end
end

module Mod1
def hello(options = {})
   super(options.merge({:mod1 => true}))
end
end

module Mod2
def hello(options = {})
   super(options.merge({:mod2 => true}))
end
end

k = Klass.new
k.hello #=> {}

k.extend(Mod1)
k.hello #=> {:mod1=>true}

k.extend(Mod2)
k.hello #=> {:mod2=>true, :mod1=>true}

I was a bit surprised that the second extend didn't clobber the first. How is this handled by the Ruby interpreter? Is it creating more than one eigenclass?

Tom

As I understand it, Ruby adds another "transparent" superclass each time you use extend or include. You can of course do that as many times as you want to get all kinds of mix-in functionality. There are some nice diagrams in the Pickaxe book that show this (I don't have it with me at the moment).

-Justin

Hi --

I've got a question regarding the inner workings of extend. Consider the following code that uses Object#extend twice:

class Klass
def hello(options = {})
  p options
end

module Mod1
def hello(options = {})
  super(options.merge({:mod1 => true}))
end

module Mod2
def hello(options = {})
  super(options.merge({:mod2 => true}))
end

k = Klass.new
k.hello #=> {}

k.extend(Mod1)
k.hello #=> {:mod1=>true}

k.extend(Mod2)
k.hello #=> {:mod2=>true, :mod1=>true}

I was a bit surprised that the second extend didn't clobber the first. How is this handled by the Ruby interpreter? Is it creating more than one eigenclass?

No, it's just inserting the modules along the method lookup chain.
You can examine it like this:

   class << k
     p ancestors
   end

which gives you:

   [Mod2, Mod1, Klass, Object, Kernel]

So Mod2 comes before Mod1, but the class (k's singleton class) still
has Mod1 mixed in.

David

···

On Thu, 20 Jul 2006, Tom Werner wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

Justin Collins wrote:

Tom Werner wrote:

I've got a question regarding the inner workings of extend. Consider the following code that uses Object#extend twice:

class Klass
def hello(options = {})
   p options
end
end

module Mod1
def hello(options = {})
   super(options.merge({:mod1 => true}))
end
end

module Mod2
def hello(options = {})
   super(options.merge({:mod2 => true}))
end
end

k = Klass.new
k.hello #=> {}

k.extend(Mod1)
k.hello #=> {:mod1=>true}

k.extend(Mod2)
k.hello #=> {:mod2=>true, :mod1=>true}

I was a bit surprised that the second extend didn't clobber the first. How is this handled by the Ruby interpreter? Is it creating more than one eigenclass?

Tom

As I understand it, Ruby adds another "transparent" superclass each time you use extend or include. You can of course do that as many times as you want to get all kinds of mix-in functionality. There are some nice diagrams in the Pickaxe book that show this (I don't have it with me at the moment).

-Justin

But the behavior of the modules is that of a subclass (being able to call super to call a method in Klass). If I were to use include inside the class definition, then I would indeed get superclass behavior.

Tom

···

--
Tom Werner
Helmets to Hardhats
Software Developer
tom@helmetstohardhats.org
www.helmetstohardhats.org

dblack@wobblini.net wrote:

Hi --

I've got a question regarding the inner workings of extend. Consider the following code that uses Object#extend twice:

class Klass
def hello(options = {})
  p options
end

module Mod1
def hello(options = {})
  super(options.merge({:mod1 => true}))
end

module Mod2
def hello(options = {})
  super(options.merge({:mod2 => true}))
end

k = Klass.new
k.hello #=> {}

k.extend(Mod1)
k.hello #=> {:mod1=>true}

k.extend(Mod2)
k.hello #=> {:mod2=>true, :mod1=>true}

I was a bit surprised that the second extend didn't clobber the first. How is this handled by the Ruby interpreter? Is it creating more than one eigenclass?

No, it's just inserting the modules along the method lookup chain.
You can examine it like this:

  class << k
    p ancestors
  end

which gives you:

  [Mod2, Mod1, Klass, Object, Kernel]

So Mod2 comes before Mod1, but the class (k's singleton class) still
has Mod1 mixed in.

David

Ah! Have I said I love Ruby today?

Thanks David.

Tom

···

On Thu, 20 Jul 2006, Tom Werner wrote:

--
Tom Werner
Helmets to Hardhats
Software Developer
tom@helmetstohardhats.org
www.helmetstohardhats.org

Tom Werner wrote:

Justin Collins wrote:

Tom Werner wrote:

I've got a question regarding the inner workings of extend. Consider the following code that uses Object#extend twice:

class Klass
def hello(options = {})
   p options
end
end

module Mod1
def hello(options = {})
   super(options.merge({:mod1 => true}))
end
end

module Mod2
def hello(options = {})
   super(options.merge({:mod2 => true}))
end
end

k = Klass.new
k.hello #=> {}

k.extend(Mod1)
k.hello #=> {:mod1=>true}

k.extend(Mod2)
k.hello #=> {:mod2=>true, :mod1=>true}

I was a bit surprised that the second extend didn't clobber the first. How is this handled by the Ruby interpreter? Is it creating more than one eigenclass?

Tom

As I understand it, Ruby adds another "transparent" superclass each time you use extend or include. You can of course do that as many times as you want to get all kinds of mix-in functionality. There are some nice diagrams in the Pickaxe book that show this (I don't have it with me at the moment).

-Justin

But the behavior of the modules is that of a subclass (being able to call super to call a method in Klass). If I were to use include inside the class definition, then I would indeed get superclass behavior.

Tom

Oh, right, nevermind.

-Justin