Object#extend inner workings

T

Tom Werner

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
(e-mail address removed)
www.helmetstohardhats.org
 
J

Justin Collins

Tom said:
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
 
T

Tom Werner

Justin said:
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
(e-mail address removed)
www.helmetstohardhats.org
 
D

dblack

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
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?

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

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
http://www.manning.com/black => RUBY FOR RAILS (reviewed on
Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
(e-mail address removed) => me
 
J

Justin Collins

Tom said:
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
 
T

Tom Werner

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
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?

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

--
Tom Werner
Helmets to Hardhats
Software Developer
(e-mail address removed)
www.helmetstohardhats.org
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top