Overridding A Method Via A Mixin

A

Andrew Stewart

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_missing-in-a-
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
 
R

Robert Klemme

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_missing-in-a-
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
 
A

Andrew Stewart

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
 
J

Jens Wille

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: (e-mail address removed)
http://www.prometheus-bildarchiv.de/
 
R

Robert Klemme

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
 
J

Jeremy McAnally

Where is this at? This is one of the most vague job listings I've ever seen.

I'm assuming Seattle?

--Jeremy

Are you a talented Ruby on Rails or mod_perl Developer looking for an
exciting opportunity? My client runs a leading enthusiasts
community/e-commerce site and they need your expertise to create new
features and functions related to social networking. This is a great
opportunity to work with a fun group and contribute to exciting
technology that's used by many!

Qualifications:

* Thorough understanding of object-oriented methodology
* Thorough understanding of MVC architectures
* Experience with coding database-backed web applications
* Expert knowledge in either mod_perl or Ruby on Rails
* Intermediate knowledge of a mod_perl templating language
* Intermediate CSS and Javascript skills
* Willingness to work in an Agile development environment
* Ability to clearly and concisely communicate technical ideas

If you are interested or know someone that is interested please have
them email a resume as a Word attachment to (e-mail address removed) or
(e-mail address removed)

Thanks!
Scot Baker
Technical Recruiting Manager
parker technical
605 Fifth Avenue South -Suite 850- Seattle, WA 98104
(e-mail address removed) | p: 206-652-1587 | f: 206-223-8227 |
c:206-915-9020
http://www.linkedin.com/in/scotbaker



--
http://www.jeremymcanally.com/

My books:
Ruby in Practice
http://www.manning.com/mcanally/

My free Ruby e-book
http://www.humblelittlerubybook.com/

My blogs:
http://www.mrneighborly.com/
http://www.rubyinpractice.com/
 
A

ara.t.howard

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_missing-in-a-
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://codeforpeople.com/
 
G

Glen Holcomb

[Note: parts of this message were removed to make it a legal post.]

As long as it's close to a Soup Kitchen they have the free lunch thing
covered.
 
R

Robert Dober

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
 
A

Andrew Stewart

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
 
A

Andrew Stewart

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
 
A

Andrew Stewart

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
 
T

Todd Benson

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
 
R

Robert Klemme

You're welcome! I really like the clean design. You know, I am more
the "Braun" type than the "Hundertwasser" type. Also, I noticed you use
Mongrel for hosting. :)
I think he was joking since Americans typically use "specialize" and
"center" instead :)

Nope. First, I am not American* and second, these are not the words I
had in mind. The "offending" word is somewhere between "organised" and
"David Allen's". To give an additional hint, it's spelled correct *and*
wrong in the *same* paragraph. :)

Cheers

robert



* Although I have to say that most English I am exposed to is probably
American English. :)
 
T

Todd Benson

Nope. First, I am not American* and second, these are not the words I
had in mind.

Got it. Easy to miss. Also, I assumed you were talking about the home page.

cheers,
Todd
 
A

Andrew Stewart

The "offending" word is somewhere between "organised" and "David
Allen's". To give an additional hint, it's spelled correct *and*
wrong in the *same* paragraph. :)

Got it. Quelle gaffe!

I like to take pride in shunning automatic spell-checking...so I
shouldn't be surprised when a fall follows :)

Kind regards,
Andy Stewart
 

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,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top