Surprising behavior when extending instances

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

Hi,

···

In message "Re: Surprising behavior when extending instances" on Sat, 14 Nov 2009 23:50:05 +0900, Jim Crossley <jim@crossleys.org> 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.

Jim Crossley:

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

···

--
Anyone who finds the MS Office ribbon intuitive is
not a member of the human species as I understand it.
                                     [William Morgan]

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?

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"

···

On Sat, Nov 14, 2009 at 9:50 AM, Jim Crossley <jim@crossleys.org> wrote:

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