From: Rick DeNatale Date: 2009-05-06T21:03:43+09:00 Subject: Re: '=||' On Wed, May 6, 2009 at 6:54 AM, Eleanor McHugh wrote: > On 6 May 2009, at 02:31, Rick DeNatale wrote: >> >> On Tue, May 5, 2009 at 8:45 PM, Eleanor McHugh >> wrote: >>> >>> On 6 May 2009, at 00:09, 7stud -- wrote: >>>> >>>> The statement: >>>> >>>> x ||= val >>>> >>>> is actually equivalent to: >>>> >>>> x = val unless x >>> >>> >>> It seems you've misunderstood what happens under the hood when using >>> augmented assignment with tables as '||=' then becomes syntactic sugar >>> for >>> 'x[] = x[] || some_other_value' and the assignment is performed via '[]=' >>> rather than '='. '[]=' will not create a key if it believes it already >>> exists and this is the cause of the behaviour you're seeing. >> >> No, if x is truthy then >> >>  x ||= expression >> >> will NOT do any assignment. >> >> The real equivalent to x ||= y >> >> is >> >> x || x = y >> >> The assignment is short-circuited. >> >> For the proof see: >> >> http://talklikeaduck.denhaven2.com/2008/04/26/x-y-redux > > Yes, for assignment that's the case. But 'x[n] ||= y' isn't an instance of > assignment in that case as can easily be demonstrated: > > class Test >  def method_missing symbol, *args >    puts "calling method #{symbol}" >  end > end > > t = Test.new > t[:a] ||= 17 > > output: calling method [] >                calling method []= > > Notice how even though method_missing returns a value and is thus 'true' the > sequence still attempts all parts of the expression, and > > t[:a] = t[:a] || 17 > > output: calling method [] >                calling method []= >                => 17 > > confirms that no short-circuited evaluation occurs. > But this is because the call to the missing [] method goes to the method missing method which returns nil. Remember that the assertion is that t[:a] ||= 17 is equivalent to (t[:a]) || (t[:a] = 17) which in turn is equivalent to: ((t.[](:a)) || (t.[]=(:a, 17)) The output of your example shows both the :[] and :[]= methods are being sent. Try this variant: class Test def method_missing symbol, *args puts "calling method #{symbol}" end def [](a) puts "in [] method" a end end t = Test.new t[:a] ||= 17 This produces the output; in [] method The short circuiting only happens if the lhs expression returns a non-truthy value. Now it's true (I think) that "a op= b" is the same as "a = a op b" in C, Ruby ain't C. Sometimes the stuff "under the hood" is a little more complicated than it first appears. -- 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