<?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: x ||= y, Redux</title>
    <link>http://talklikeaduck.denhaven2.com/articles/2008/04/26/x-y-redux</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>In Ruby, it's not the dog, it's the tricks!</description>
    <item>
      <title>x ||= y, Redux</title>
      <description>A while back there was quite a thread on the Ruby-lang mailing list about the real semantics of the expression.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;a[x] ||= some_value&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In many books and articles on Ruby the form:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;a &amp;lt;op&amp;gt;= b&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where &amp;LT;op&amp;GT; is an operator like + Is described as syntactic sugar:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;a = a &amp;lt;op&amp;gt; b&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While this is true in most cases, it &lt;strong&gt;isn&amp;#8217;t&amp;#8217;&lt;/strong&gt; true if the operator is ||.&lt;/p&gt;
&lt;p&gt;This comes to light when the left hand side is a method call, to an accessor, or accessor-like method. For example&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;h = Hash.new(&amp;quot;hello&amp;quot;)
h[:fred] ||= &amp;quot;&amp;quot;
h #=&amp;gt; {}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some find it surprising that the assignment doesn&amp;#8217;t cause the hash to have :fred as a key. What this code snippet shows is that the assignment doesn&amp;#8217;t actually assign anything if the left hand expression returns a logically true value.  A Hash with a default value will return the default value when accessed by any key which is not present in the hash.  Since h[:fred] returns the default value, the assignment doesn&amp;#8217;t happen.&lt;/p&gt;
&lt;p&gt;This affects any object which has &amp;#8216;accessor&amp;#8217; methods. Here&amp;#8217;s a class cooked up just to explore this aspect of Ruby.&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;class ChattyCathy

  def initialize(x=nil)
    @x = x
    puts &amp;quot;created x is now #{x.inspect}&amp;quot;
  end

  def x
    puts &amp;quot;x read x is #{@x.inspect}&amp;quot;
    @x
  end

  def x=(val)
    puts &amp;quot;x written, now #{val.inspect}&amp;quot;
    @x = val
  end
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The purpose of this class is simply to let us see exactly when the x attribute is read and written. Now if we run this code&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;c = ChattyCathy.new(42)
puts &amp;quot;about to evaluate c.x ||= 43&amp;quot;
c.x ||= 43
c = ChattyCathy.new
puts &amp;quot;about to evaluate c.x ||= 43&amp;quot;
c.x ||= 43&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We get the following output:&lt;/p&gt;
&lt;xmp&gt;
    created x is now 42
    about to evaluate c.x ||= 43
    x read x is 42
    created x is now nil
    about to evaluate c.x ||= 43
    x read x is nil
    x written, now 43
&lt;/xmp&gt;
&lt;p&gt;Which clearly illustrates just when the assignment actually happens.&lt;/p&gt;
&lt;h2&gt;The real expansion of x ||= y&lt;/h2&gt;
&lt;p&gt;Matz explains that the real expansion of x ||= y is:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;x || x = y&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The expectation that x ||= y is the same as x = x || y, does seem reasonable to someone &amp;#8216;coming from&amp;#8217; C or one of it&amp;#8217;s derivative languages.  As far as I can determine, C introduced the notion of assignment operators like += and -=.  And K&amp;#38;R defined these assignment operators as a shorthand for x = x + y, etc.&lt;/p&gt;
&lt;p&gt;On the other hand, although C has logical operators || and &amp;#38;&amp;#38; which, like Ruby have &amp;#8216;short-circuit&amp;#8217; evaluation, it doesn&amp;#8217;t allow ||=, or &amp;#38;&amp;#38;= as assignment operators.&lt;/p&gt;&lt;p&gt;Since || is a &amp;#8216;short-circuit&amp;#8217; boolean operator, the left hand operand expression is only evaluated if the right hand operand expression evaluates to a logically false value, i.e. either nil or false.&lt;/p&gt;
&lt;p&gt;The way that Matz included ||= as an assignment operator makes perfect sense to me. The ||= assignment operator reserves the short-circuit nature of ||.&lt;/p&gt;
&lt;h2&gt;So what about x &amp;#38;&amp;#38;= y&lt;/h2&gt;
&lt;p&gt;Although I haven&amp;#8217;t seen this discussed anywhere, &amp;#38;&amp;#38;= in Ruby has similar behavior:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;c = ChattyCathy.new
puts &amp;quot;about to evaluate c.x &amp;amp;&amp;amp;= true&amp;quot;
c.x &amp;amp;&amp;amp;= true
puts &amp;quot;about to evaluate c.x = \&amp;quot;hi\&amp;quot;&amp;quot;
c.x = &amp;quot;Hi&amp;quot;
puts &amp;quot;about to evaluate c.x &amp;amp;&amp;amp;= true&amp;quot;
c.x &amp;amp;&amp;amp;= true&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;xmp&gt;
    created x is now nil
    about to evaluate c.x &amp;#38;&amp;#38;= true
    x read x is nil
    about to evaluate c.x = &amp;#8220;hi&amp;#8221; 
    x written, now &amp;#8220;Hi&amp;#8221; 
    about to evaluate c.x &amp;#38;&amp;#38;= true
    x read x is &amp;#8220;Hi&amp;#8221; 
    x written, now true
&lt;/xmp&gt;
&lt;p&gt;So the expansion of x &amp;#38;&amp;#38;= y is x &amp;#38;&amp;#38; x = y&lt;/p&gt;</description>
      <pubDate>Sat, 26 Apr 2008 11:11:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:ecdb3ccb-c373-4025-8709-3f5ad3ddb52c</guid>
      <author>Rick DeNatale</author>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/04/26/x-y-redux</link>
      <category>ruby</category>
      <trackback:ping>http://talklikeaduck.denhaven2.com/articles/trackback/495</trackback:ping>
    </item>
    <item>
      <title>"x ||= y, Redux" by Federico</title>
      <description>&lt;p&gt;Rick,&lt;/p&gt;


	&lt;p&gt;You&amp;#8217;re right, it will in fact call x= and I hadn&amp;#8217;t noticed that.&lt;/p&gt;


	&lt;p&gt;And yes, C has ho ||=, that&amp;#8217;s why I said &amp;#8220;would&amp;#8221; as in &amp;#8220;following the usual rules for the other operators, it would be&amp;#8230;&amp;#8221; but I should&amp;#8217;ve expressed in a clearer way :)&lt;/p&gt;</description>
      <pubDate>Mon, 28 Apr 2008 10:01:20 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:5530df4f-fad6-42f3-a6fc-2814955e9ea9</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/04/26/x-y-redux#comment-4833</link>
    </item>
    <item>
      <title>"x ||= y, Redux" by Rick DeNatale</title>
      <description>&lt;p&gt;Federico,&lt;/p&gt;


In your expansion
h[:bar] = h[:bar] || &#8220;bla&#8221;
Just because the &amp;#8220;bla&amp;#8221; doesn&amp;#8217;t get evaluated, doesn&amp;#8217;nt mean that the assignment doesn&amp;#8217;t happen.  Let&amp;#8217;s compare using my ChattyCathy class:

&lt;pre&gt;&lt;code&gt;c = ChattyCathy.new(1)
puts &amp;quot;about to evaluate c.x = c.x || 2&amp;quot;
c.x = c.x || 2
puts &amp;quot;about to evaluate c.x ||= 3&amp;quot;
c.x ||= 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which outputs:&lt;/p&gt;
&lt;br /&gt;
&lt;br /&gt;created x is now 1
&lt;br /&gt;about to evaluate c.x = c.x || 2
&lt;br /&gt;x read x is 1
&lt;br /&gt;x written, now 1
&lt;br /&gt;about to evaluate c.x ||= 3
&lt;br /&gt;x read x is 1
&lt;br /&gt;&lt;br /&gt;    
&lt;p&gt;So in your expansion, the assignment does in fact happen.  Note here that I&amp;#8217;m using assignment in the broad sense here.  Since in this form of assignment, the Ruby parser is turning the assignment in to a method call to the x= method.&lt;/p&gt;
&lt;p&gt;Also for what it&amp;#8217;s worth, there is no K&amp;#38;R expansion of x ||= y, because while C allows x |= y and x &amp;#38;= y, it does not allow x ||= y or x &amp;#38;&amp;#38;= y&lt;/p&gt;</description>
      <pubDate>Mon, 28 Apr 2008 08:01:32 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:31adde07-84e7-4429-b258-5cf9aac424be</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/04/26/x-y-redux#comment-4831</link>
    </item>
    <item>
      <title>"x ||= y, Redux" by Jeff</title>
      <description>&lt;p&gt;So is the main advantage of the unexpected implementation,  &lt;code&gt;x || x = y&lt;/code&gt;, the fact that the interpreter can sometimes avoid the assignment operation that would must always occur for &lt;code&gt;x = x || y&lt;/code&gt;?&lt;/p&gt;


	&lt;p&gt;Thanks!&lt;/p&gt;</description>
      <pubDate>Sun, 27 Apr 2008 20:37:52 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:f3eb1391-1e96-4ffa-a4e7-9b7e0ed213d7</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/04/26/x-y-redux#comment-4828</link>
    </item>
    <item>
      <title>"x ||= y, Redux" by she/she@hotmail.com</title>
      <description>&lt;p&gt;You know what?&lt;/p&gt;


	&lt;p&gt;I think this brain power of figuring out what it does should be better spent on designing and documenting ;)&lt;/p&gt;


	&lt;p&gt;Reminds me of the old C adage where people didnt use enough ()&lt;/p&gt;


	&lt;p&gt;Luckily I can write my ruby code without having to worry about that.&lt;/p&gt;


	&lt;p&gt;Btw your way sets .default for hash, I think not every visitor will know that:&lt;/p&gt;


	&lt;p&gt;h = Hash.new(&amp;#8220;hello&amp;#8221;) # =&amp;gt; {}
h[&amp;#8220;a&amp;#8221;]                # =&amp;gt; &amp;#8220;hello&amp;#8221;&lt;/p&gt;


	&lt;p&gt;You see every key, even if it does not exist, will return that default value&lt;/p&gt;


	&lt;p&gt;And knowing this, the
h[:fred] ||= &amp;#8221;&amp;#8221; 
 doesnt look as confusing anymore (although I still think it looks damn ugly.)&lt;/p&gt;</description>
      <pubDate>Sun, 27 Apr 2008 09:01:54 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:e25bb123-5552-4073-bea7-fa2e27fb6618</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/04/26/x-y-redux#comment-4827</link>
    </item>
    <item>
      <title>"x ||= y, Redux" by Federico</title>
      <description>&lt;p&gt;&amp;gt;&amp;gt; Some find it surprising that the assignment doesn&#8217;t cause the hash to have :fred as a key. What this code snippet shows is that the assignment doesn&#8217;t actually assign anything if the left hand expression returns a logically true value.&lt;/p&gt;


	&lt;p&gt;Maybe I&amp;#8217;m misreading your post but I don&amp;#8217;t quite get why the example fails to show the expansion:&lt;/p&gt;


	&lt;p&gt;h = Hash.new(&amp;#8220;foo&amp;#8221;)
h[:bar] ||= &amp;#8220;bla&amp;#8221;&lt;/p&gt;


	&lt;p&gt;If I expand that to:&lt;/p&gt;


	&lt;p&gt;h[:bar] = h[:bar] || &amp;#8220;bla&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Then it makes perfect sense that the assignment doesn&amp;#8217;t happen. As I see it, h[:bar] does exists (it&amp;#8217;s != nil) so it never has to evaluate the second choice (&amp;#8220;bla&amp;#8221;).&lt;/p&gt;


	&lt;p&gt;Carrying on with it, the K&amp;#38;R expansion for x ||= y would be:&lt;/p&gt;


	&lt;p&gt;x = x || y&lt;/p&gt;


	&lt;p&gt;We can say that that is:&lt;/p&gt;


	&lt;p&gt;x = x || x = y&lt;/p&gt;


	&lt;p&gt;And x = x &amp;lt;=&amp;gt; x (in Ruby those 2 are the same thing), so:&lt;/p&gt;


	&lt;p&gt;x || x = y&lt;/p&gt;


	&lt;p&gt;Which I think shows that the propsed expansion by Matz that you quote is the same as the original one.&lt;/p&gt;


	&lt;p&gt;Maybe I missed something?&lt;/p&gt;</description>
      <pubDate>Sat, 26 Apr 2008 13:10:18 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:b030d019-f00f-42d0-9cf3-7303fa5413c0</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2008/04/26/x-y-redux#comment-4826</link>
    </item>
  </channel>
</rss>
