From: Rick DeNatale Date: 2008-05-02T22:18:13+09:00 Subject: Re: Please explain nuances of ||= On Fri, May 2, 2008 at 8:35 AM, Simon Krahnke wrote: > * Rick DeNatale (03:26) schrieb: > > > > 1) In Ruby x ||= y does no assignment if x evaluates to true, and x > > &&= y does no assignment if x evaluates to true. > > Eh, what? You are confusing me. > > &&= does an assignment only if x evaluates to true. Yes, that was a typo on my part, it should have read "and x &&= y does not assignment if x evaluates to false." > The question of if there is an assignment in x = x is purely > metaphysical: there is no way to tell. If x is a simple variable, that's correct, however if x is actually an "attribute accessor" like foo.bar ||= y or foo[:bar] ||= y Then you can tell if the bar= or []= method which gets invoked on 'assignment' has side effects. > > 2) x || x = y, and x && x = y are much better first approximations of > > how x ||= y and x &&= y than x = x || y, and x = x && y, despite what > > K&R say. > > And doesn't explain why x springs into existence, if didn't exist > before. This is because the Ruby parser recognizes the variable as local when it sees it as the POTENTIAL assignee. In the first chunk below, the a = 1 never got executed because of the if false modifier, but the parser still picked up a 'declaration' of a as a local variable. defined? a # => nil a = 1 if false defined? a # => "local-variable" a # => nil defined? b # => nil b ||= 1 defined? b # => "local-variable" b # => 1 defined? c # => nil c &&= 1 defined? c # => "local-variable" c # => nil of course in the case of d.e ||= g or h[1] ||= i There's no question of the method 'springing' into existence, d.e, d.e=, h[], and h[]= will either work or throw a method not found if and when they are called. > > 3) I say first approximations because of David Black's observation > > that x ||= y and x || x = y differ when x is undefined. > > Right, but x = x || y doesn't. > > The only thing special about x ||= y is that x is only ever evaluated > once. But that's special in every op=. Except that, if x is really obj.foo, or obj[a] then the notion of x getting evaluated once is a little squirrelly, because reading x is done by evaluating obj.foo or obj.[](a), and writing it (should the assignment actually occur) is done by evaluating obj.foo=(y) or obj.[]=(a,y) The fact that x = y is actually a method call under some circumstances is what's special about Ruby, and why simply extending K&Rs explanation of op= misses the point. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/