jimc
November 14, 2009, 3:50pm
#1
This surprised me:
module English; def say; “yes”; end; end
module French; def say; “oui”; end; end
x = Object.new
x.extend English
x.say # “yes”
x.extend French
x.say # “oui”
x.extend English
x.say # “oui”
What wrong assumptions am I making that this surprises me? What is
the more elegant “Ruby way” of alternating an object’s behavior at
runtime?
Thanks,
Jim
jimc
November 14, 2009, 5:15pm
#2
Hi,
In message “Re: Surprising behavior when extending instances”
on Sat, 14 Nov 2009 23:50:05 +0900, Jim C. [email protected]
writes:
|This surprised me:
|
| module English; def say; “yes”; end; end
| module French; def say; “oui”; end; end
| x = Object.new
| x.extend English
| x.say # “yes”
| x.extend French
| x.say # “oui”
| x.extend English
| x.say # “oui”
|
|What wrong assumptions am I making that this surprises me? What is
|the more elegant “Ruby way” of alternating an object’s behavior at
|runtime?
#extend (and #include ) include a module only once.
matz.
jimc
November 14, 2009, 5:26pm
#3
Jim C.:
This surprised me:
module English; def say; “yes”; end; end
module French; def say; “oui”; end; end
x = Object.new
x.extend English
This adds English to the front of the method look-up path.
x.say # “yes”
At this point, the #say method is first looked-up in English.
x.extend French
This adds French to the front of the method look-up path.
x.say # “oui”
At this point, the #say method is first looked-up in French.
x.extend English
Hey, English is already in the method look-up path, no need to add it!
x.say # “oui”
Oui, French is still at the front of the method look-up path…
What wrong assumptions am I making that this surprises me?
That the second #extend call moved English
to the front of the method look-up path.
What is the more elegant “Ruby way” of
alternating an object’s behavior at runtime?
I don’t have hand-on experience, and there probably is a simple,
canonical way, but I’d start with looking at Object#instance_eval.
— Shot
jimc
November 14, 2009, 5:39pm
#4
On Sat, Nov 14, 2009 at 9:50 AM, Jim C. [email protected] wrote:
x.say # “oui”
What wrong assumptions am I making that this surprises me?
Matz has already explained that module inclusion is a one-time only
deal.
Here’s a bit on why that is.
http://talklikeaduck.denhaven2.com/2007/11/03/a-chat-with-matz-classs-variable-reversion-and-a-mystery-explained
What is
the more elegant “Ruby way” of alternating an object’s behavior at
runtime?
I’d use a form of delegation
module English; def self.agree; “yes”; end; end
module French; def self.agree; “oui”; end; end
class Speaker
attr_accessor :language
def initialize(language = English)
self.language = language
end
def say
language.agree
end
def speak(language)
self.language = language
end
end
jack = Speaker.new
jacques = Speaker.new(French)
jack.say # => “yes”
jacques.say # => “oui”
jack.speak(French)
jacques.speak(English)
jack.say # => “oui”
jacques.say # => “yes”
jack.speak(English)
jacques.speak(French)
jack.say # => “yes”
jacques.say # => “oui”
–
Rick DeNatale
Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale