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