[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Overridding A Method Via A Mixin

Andrew Stewart

1/15/2008 5:33:00 PM

Hi Everyone,

I believe one can add methods to a class by including a module but
not override existing methods. Indeed Dr Nic said as much here:

http://ruby.tie-rack.org/6/safely-overriding-method_mis...
class-that-already-has-it/#comment-7

Here's some code that demonstrates this.

class Foo
def answer
42
end
end

module Bar
def answer
"What was the question?"
end

def to_s
"bar"
end
end

Foo.send :include, Bar
f = Foo.new
f.answer # => 42, not "What was the question?"
f.to_s # => "bar", not "#<Foo:0x731248>"


Why aren't existing methods overridden? And where could I have
looked to find out the answer for myself (perhaps somewhere in Ruby's
source?)?

Thanks and regards,
Andy

-------
http://airbladeso...




13 Answers

Robert Klemme

1/15/2008 5:37:00 PM

0

On 15.01.2008 18:32, Andrew Stewart wrote:
> Hi Everyone,
>
> I believe one can add methods to a class by including a module but
> not override existing methods. Indeed Dr Nic said as much here:
>
> http://ruby.tie-rack.org/6/safely-overriding-method_mis...
> class-that-already-has-it/#comment-7
>
> Here's some code that demonstrates this.
>
> class Foo
> def answer
> 42
> end
> end
>
> module Bar
> def answer
> "What was the question?"
> end
>
> def to_s
> "bar"
> end
> end
>
> Foo.send :include, Bar
> f = Foo.new
> f.answer # => 42, not "What was the question?"
> f.to_s # => "bar", not "#<Foo:0x731248>"
>
>
> Why aren't existing methods overridden? And where could I have
> looked to find out the answer for myself (perhaps somewhere in Ruby's
> source?)?

Because of the position in the inheritance hierarchy:

irb(main):001:0> module Bar;end
=> nil
irb(main):002:0> class Foo
irb(main):003:1> include Bar
irb(main):004:1> end
=> Foo
irb(main):005:0> Foo.ancestors
=> [Foo, Bar, Object, Kernel]

Methods defined in Foo are always found before their counterparts in
included modules. Consequently you can override super class methods
with a module.

Kind regards

robert

Andrew Stewart

1/15/2008 6:10:00 PM

0


On 15 Jan 2008, at 17:40, Robert Klemme wrote:
> Because of the position in the inheritance hierarchy:
>
> irb(main):001:0> module Bar;end
> => nil
> irb(main):002:0> class Foo
> irb(main):003:1> include Bar
> irb(main):004:1> end
> => Foo
> irb(main):005:0> Foo.ancestors
> => [Foo, Bar, Object, Kernel]
>
> Methods defined in Foo are always found before their counterparts
> in included modules. Consequently you can override super class
> methods with a module.

Aha, of course. Thank you for the clear explanation.

I really should have worked that one out myself!

With regards,
Andy Stewart

-------
http://airbladeso...




Jens Wille

1/15/2008 6:15:00 PM

0

hi andrew!

Andrew Stewart [2008-01-15 18:32]:
> I believe one can add methods to a class by including a module
> but not override existing methods.
well, you *can* override them explicitly:

module Bar
def self.included(base)
methods_to_override = %w[answer]
# or even <tt>instance_methods(false)</tt>

methods_to_override.each { |method|
base.send(:define_method, method, instance_method(method))
}
end
end

if that's what you want... ;-)

cheers
jens

--
Jens Wille, Dipl.-Bibl. (FH)
prometheus - Das verteilte digitale Bildarchiv für Forschung & Lehre
Kunsthistorisches Institut der Universität zu Köln
Albertus-Magnus-Platz, D-50923 Köln
Tel.: +49 (0)221 470-6668, E-Mail: jens.wille@uni-koeln.de
http://www.prometheus-bild...

Robert Klemme

1/15/2008 6:35:00 PM

0

On 15.01.2008 19:10, Andrew Stewart wrote:
> On 15 Jan 2008, at 17:40, Robert Klemme wrote:
>> Because of the position in the inheritance hierarchy:
>>
>> irb(main):001:0> module Bar;end
>> => nil
>> irb(main):002:0> class Foo
>> irb(main):003:1> include Bar
>> irb(main):004:1> end
>> => Foo
>> irb(main):005:0> Foo.ancestors
>> => [Foo, Bar, Object, Kernel]
>>
>> Methods defined in Foo are always found before their counterparts
>> in included modules. Consequently you can override super class
>> methods with a module.
>
> Aha, of course. Thank you for the clear explanation.

You're welcome!

> I really should have worked that one out myself!

Ah, no worries. Once in a while this just happens to all of us.

Btw, you got a nice website there (with a typo on the vortex page *g*).

Kind regards

robert

ara.t.howard

1/15/2008 7:33:00 PM

0


On Jan 15, 2008, at 10:32 AM, Andrew Stewart wrote:

> Hi Everyone,
>
> I believe one can add methods to a class by including a module but
> not override existing methods. Indeed Dr Nic said as much here:
>
> http://ruby.tie-rack.org/6/safely-overriding-method_mis...
> class-that-already-has-it/#comment-7



i personally avoid aliases like that - they stack when you double
require or double include a module and throw into a loop. this kind
of thing can be done safely and generically using a variable for the
previous method that's protected from the gc and a lookup in the new
method:



cfp:~ > cat a.rb
class A
def foo
p "A.foo"
end
end
class B
end

module M
NoGC = []

def self.included other
other.module_eval do
if((foo = instance_method 'foo' rescue false))
NoGC.push foo
supra = "ObjectSpace._id2ref(#{ foo.object_id }).bind
(self).call(*a, &b)"
end
eval <<-code
def foo *a, &b
#{ supra }
p "M.foo"
end
code
end
end
end

A.send :include, M
B.send :include, M

A.new.foo
B.new.foo


cfp:~ > ruby a.rb
"A.foo"
"M.foo"
"M.foo"


this allows you to both override and super up, in any combination,
with a method injected late into a class hierarchy


kind regards


a @ http://codeforp...
--
it is not enough to be compassionate. you must act.
h.h. the 14th dalai lama




Robert Dober

1/15/2008 10:08:00 PM

0

On Jan 15, 2008 8:33 PM, ara.t.howard <ara.t.howard@gmail.com> wrote:

> this allows you to both override and super up, in any combination,
> with a method injected late into a class hierarchy
Actually whenever these issues come up I wonder why we still define
methods in classes?
Either, using pure Ruby implementening all functionality im Modules
(with the dangerous pitfall of double inclusion, or just using Traits
Composition would just end all of that kind of complexity) But even I
do not use my Traits package, old habits are difficult to lose
indeed....
Cheers
Robert
--
http://ruby-smalltalk.blo...

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Andrew Stewart

1/16/2008 4:01:00 PM

0


On 15 Jan 2008, at 18:15, Jens Wille wrote:
> well, you *can* override them explicitly:
>
> module Bar
> def self.included(base)
> methods_to_override = %w[answer]
> # or even <tt>instance_methods(false)</tt>
>
> methods_to_override.each { |method|
> base.send(:define_method, method, instance_method(method))
> }
> end
> end
>
> if that's what you want... ;-)

There's always a way! Thanks Jens, that's neat.

Regards,
Andy Stewart

-------
http://airbladeso...




Andrew Stewart

1/16/2008 4:06:00 PM

0


On 15 Jan 2008, at 18:39, Robert Klemme wrote:
> Btw, you got a nice website there (with a typo on the vortex page
> *g*).

Thanks! You are kind to say so.

I can't find that typo though...are you pulling my leg? :)

With regards,
Andy Stewart

-------
http://airbladeso...




Andrew Stewart

1/16/2008 4:40:00 PM

0


On 15 Jan 2008, at 19:33, ara.t.howard wrote:
> i personally avoid aliases like that - they stack when you double
> require or double include a module and throw into a loop. this
> kind of thing can be done safely and generically using a variable
> for the previous method that's protected from the gc and a lookup
> in the new method:

I see. That sounds much more sensible.

> cfp:~ > cat a.rb
> class A
> def foo
> p "A.foo"
> end
> end
> class B
> end
>
> module M
> NoGC = []
>
> def self.included other
> other.module_eval do
> if((foo = instance_method 'foo' rescue false))
> NoGC.push foo
> supra = "ObjectSpace._id2ref(#{ foo.object_id }).bind
> (self).call(*a, &b)"
> end
> eval <<-code
> def foo *a, &b
> #{ supra }
> p "M.foo"
> end
> code
> end
> end
> end
>
> A.send :include, M
> B.send :include, M
>
> A.new.foo
> B.new.foo
>
>
> cfp:~ > ruby a.rb
> "A.foo"
> "M.foo"
> "M.foo"
>
>
> this allows you to both override and super up, in any combination,
> with a method injected late into a class hierarchy

Wonderful!

I should confess that I haven't entirely convinced myself that I
understand your construction of supra. Given that you have the
unbound method in the foo variable, is the reason why you can't bind
foo directly, perhaps like this:

supra = "#{foo}.bind(self).call(*a, &b)"

...because there's no way to write the string so it eval's the way we
want it to?

Thank you for the enlightenment :)

Regards,
Andy Stewart

-------
http://airbladeso...




Todd Benson

1/16/2008 6:19:00 PM

0

On Jan 16, 2008 10:06 AM, Andrew Stewart <boss@airbladesoftware.com> wrote:
>
> On 15 Jan 2008, at 18:39, Robert Klemme wrote:
> > Btw, you got a nice website there (with a typo on the vortex page
> > *g*).
>
> Thanks! You are kind to say so.
>
> I can't find that typo though...are you pulling my leg? :)

I think he was joking since Americans typically use "specialize" and
"center" instead :-)

Todd