<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Talk Like A Duck: A Subtle Change to Mixin Semantics in Ruby 1.9</title>
    <link>http://talklikeaduck.denhaven2.com/articles/2006/10/09/a-subtle-change-to-mixin-semantics-in-ruby-1-9</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>In Ruby, it's not the dog, it's the tricks!</description>
    <item>
      <title>A Subtle Change to Mixin Semantics in Ruby 1.9</title>
      <description>&lt;p&gt;I&amp;#8217;ve been working on a little tool to peek behind the curtain and see a bit of what&amp;#8217;s going on behind the scenes in the standard Ruby implementation (i.e &amp;#8216;ruby&amp;#8217; as opposed to &amp;#8216;Ruby&amp;#8217;)&lt;/p&gt;


	&lt;p&gt;While doing this I was looking at the code which ruby runs when you include a module in a class or another module.  I noticed that ruby 1.8 was going to some pains &lt;b&gt;not&lt;/b&gt; to move the proxy for an included module in the inheritance chain.&lt;/p&gt;


	&lt;p&gt;To verify what my eyes seemed to be telling me, I wrote a silly little test program which created a module with one method, and several classes.&lt;/p&gt;


	&lt;p&gt;This test verified my reading of the 1.8 code.  I then tried the same test using the latest ruby 1.9 and found that module mixin semantics have changed.&lt;/p&gt;


	&lt;p&gt;Read on&lt;/p&gt;


Here&amp;#8217;s my test code:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;module M1
  def foo
    &amp;quot;foo in M1&amp;quot;
  end
end

module M2
  include M1
end

class C1
  def foo
    &amp;quot;foo in C1&amp;quot;
  end
end

class C2 &amp;lt; C1
  include M1
end

class C3 &amp;lt; C2
  def foo
    &amp;quot;foo in C3&amp;quot;
  end
end

class C4 &amp;lt; C3
  include M1
end

class C5 &amp;lt; C3
  include M2
end

puts &amp;quot;C1 #{C1.new.foo}&amp;quot;
puts &amp;quot;C2 #{C2.new.foo}&amp;quot;
puts &amp;quot;C3 #{C3.new.foo}&amp;quot;
puts &amp;quot;C4 #{C4.new.foo}&amp;quot;
puts &amp;quot;C5 #{C5.new.foo}&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Module mix-in semantics in ruby 1.8&lt;/h2&gt;

And here&amp;#8217;s what we get when we run this using ruby 1.8, with commentary interspersed:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;rick@frodo:/public/rubyscripts$ ruby include_test.rb
C1 foo in C1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Note that class C1 defines a method :foo. There should be no surprise that invoking :foo on an instance of C1 gets that definition.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;C2 foo in M1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
C2 subclasses C1, and also includes module M1, which &lt;b&gt;also&lt;/b&gt; defines a method :foo.  We can see that M1&amp;#8217;definition takes precedence. The search order is, first a singleton class if it exists, then the object&amp;#8217;s class, then any modules included in that class in the reverse order of inclusion, then the superclass, etc.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;C3 foo in C3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
C3 subclasses C2 and overrides the foo method. Again no surprise.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;C4 foo in C3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Here&amp;#8217;s the case which illustrates what I found in the 1.8 code.  C4, a subclass of C3 again includes M1, but instances of C4 resolve foo to the method in C3.  This seems to be odd, since by including M1 in C4, I would expect M1&amp;#8217;s methods to take precedence over those of the superclass.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;C5 foo in C3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
This final case is a class, C5 which like C4 subclasses C3, and includes a second module M2, which in turn includes M1.  Once again foo resolves to the method defined in C3.
&lt;p&gt;I find the 1.8 implementation counter-intuitive.  As I said it goes to lengths to find an existing inclusion of a module, and re-use it, even if that inclusion was in a superclass.
&lt;h2&gt;Change in ruby 1.9&lt;/h2&gt;
I guess that the core-team agreed with that assessment, or at least the current 1.9 implementation seems to do insertion in a less surprising manner.  Here&amp;#8217;s the result of running the same code with ruby 1.9:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;$ ruby1.9 include_test.rb
C1 foo in C1
C2 foo in M1
C3 foo in C3
C4 foo in M1
C5 foo in M1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

For easier comparison here&amp;#8217;s the output from ruby 1.8 without commentary.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;$ ruby include_test.rb
C1 foo in C1
C2 foo in M1
C3 foo in C3
C4 foo in C3
C5 foo in C3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;I don&amp;#8217;t know about you, but this seems more natural to me.&lt;/p&gt;


	&lt;p&gt;It&amp;#8217;s a subtle change.  I don&amp;#8217;t know how much ruby code re-mixes in modules. I only wrote my test code to verify a quirk I saw in reading the ruby sources.&lt;/p&gt;


	&lt;p&gt;Since the ruby 1.8 implementation made doing so ineffective, I doubt that there is much code which does, but if there is such code, it might break under 1.9, but I think that the change is a good one.&lt;/p&gt;</description>
      <pubDate>Mon, 09 Oct 2006 16:07:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:96bd51aa-2993-407b-8ee3-6c6605b14777</guid>
      <author>Rick DeNatale</author>
      <link>http://talklikeaduck.denhaven2.com/articles/2006/10/09/a-subtle-change-to-mixin-semantics-in-ruby-1-9</link>
      <category>ruby</category>
      <category>semantics</category>
      <category>inheritance</category>
      <category>mixins</category>
      <category>changesinruby1.9</category>
      <trackback:ping>http://talklikeaduck.denhaven2.com/articles/trackback/48</trackback:ping>
    </item>
    <item>
      <title>"A Subtle Change to Mixin Semantics in Ruby 1.9" by binary42</title>
      <description>While this hasn't been addressed like this before, it has been brought up multiple times but those seeking reason to the behavior 1.8 and bellow makes when including the same module multiple times. It has some nasty side effects for the uninitiated.

1.9 is fortunately just simplifying the notion of modules by removing this specific constraint. Somedays I wish I could move production code over to 1.9 today... some of these changes are so nice! :-)

Thanks for the good write-up.</description>
      <pubDate>Mon, 09 Oct 2006 18:12:07 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:844f3be6-5df5-421e-8dc2-c6123a00fc72</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2006/10/09/a-subtle-change-to-mixin-semantics-in-ruby-1-9#comment-20</link>
    </item>
  </channel>
</rss>
