extend weirdness?

I

Ian White

Hi Group,

This code:
module Foo
def self.included(base)
base.class_eval <<-end_eval
def self.meth
"Foo"
end
end_eval
end
end

module Bar
def self.included(base)
base.class_eval do
extend ClassMethods
end
end

module ClassMethods
def meth
"Bar"
end
end
end

class A
include Foo
include Bar
end

puts A.meth

produces:
Foo

whereas I would expect it to produce "Bar"

Can anyone explain what's going on here? i.e. Why the latter extend
with Bar doesn't over-write the class method introduced by Foo

Cheers,
Ian White
 
I

Ian White

The previous post is using a rails-style idiom, which is unnecessarily
complex for the problem at hand.
Here's a simpler example to the same effect:

module Foo
def self.included(base)
class<<base
def meth
"Foo"
end
end
end
end

module Bar
def meth
"Bar"
end
end

class A
include Foo
extend Bar
end

puts A.meth

Which produces "Foo"

There's a workaround (remove the method by hand):

module Bar
def self.extended(base)
class<<base
remove_method :meth
end
end
end

But this workaround does what I'd expect Ruby to do (overwrite any
existing methods when extending)

I'm confused - is this expected behaviour?

Cheers,
Ian

ps.

$ ruby --version
ruby 1.8.5 (2006-08-25) [powerpc-darwin8.7.0]
 
D

dblack

Hi --

The previous post is using a rails-style idiom, which is unnecessarily
complex for the problem at hand.
Here's a simpler example to the same effect:

module Foo
def self.included(base)
class<<base
def meth
"Foo"
end
end
end
end

module Bar
def meth
"Bar"
end
end

class A
include Foo
extend Bar
end

puts A.meth

Which produces "Foo"

There's a workaround (remove the method by hand):

module Bar
def self.extended(base)
class<<base
remove_method :meth
end
end
end

But this workaround does what I'd expect Ruby to do (overwrite any
existing methods when extending)

I'm confused - is this expected behaviour?

Yes. When you send a message to A, it searches for a
corresponding method in:

its singleton class
modules mixed into its singleton class
its "birth class" (Class in this case)
modules mixed into its birth class
etc. (up to Object and Kernel)

in that order. When you do "extend Bar", you've inserted Bar as one
of the modules mixed into the singleton class of A (line 2). But when
you do include Foo, you insert the method "meth" directly into the
singleton class (line 1). Therefore, that version of "meth" will
always take priority, no matter how many modules you mix in or in what
order.


David

--
Q. What's a good holiday present for the serious Rails developer?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
aka The Ruby book for Rails developers!
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
I

Ian White

Thanks David for that very clear explanation, I am no longer confused.

Cheers,
Ian
 
V

Vincent Fourmond

Ian said:
Hi Group,

This code:
module Foo
def self.included(base)
base.class_eval <<-end_eval
def self.meth
"Foo"
end
end_eval
end
end

module Bar
def self.included(base)
base.class_eval do
extend ClassMethods
end
end

module ClassMethods
def meth
"Bar"
end
end
end

class A
include Foo
include Bar
end

puts A.meth

produces:
Foo

whereas I would expect it to produce "Bar"

Can anyone explain what's going on here? i.e. Why the latter extend
with Bar doesn't over-write the class method introduced by Foo

The answer is simple: extend doesn't overwrite methods, it just
includes the module for the singleton object. As there is already a
singleton method 'meth' defined in the singleton object A, this method
is used systematically in method calls.

Does that explain your result ? For information, extend is

rb_extend_object(obj, module)
VALUE obj, module;
{
rb_include_module(rb_singleton_class(obj), module);
}

It is basically like

class << self
include Something
end

Cheers,

Vince
 

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,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top