The ||= assignment operator

D

David A. Black

Hi --

Huh?

My understanding has always been that x ||= y is shorthand for x = x
|| y just as x += y is shorthand for x = x + y. That also seems to be
the understanding of the "Programming Ruby" text (p. 125 of the
latest). In other words, an assignment will take place even if it's
superfluous.

Strictly speaking, it isn't shorthand for either, since there are
cases where the expansion will fail but ||= won't because x isn't
initialized. However, discounting that, the expansion is:

x || x = y

The only time this matters is with hashes that have default values. In
every other case, as far as I know, x = x || y also describes what's
happening. But the expansion which describes *every* case is x || x =
y.

I wrote a blog post about this recently:
http://dablog.rubypal.com/2008/3/25/a-short-circuit-edge-case
(I changed || to or for some reason, which screws up the precedence,
but I inserted corrections later.)


David

--
Rails training from David A. Black and Ruby Power and Light:
ADVANCING WITH RAILS April 14-17 New York City
INTRO TO RAILS June 9-12 Berlin
ADVANCING WITH RAILS June 16-19 Berlin
See http://www.rubypal.com for details and updates!
 
J

Joel VanderWerf

David said:
The only time this matters is with hashes that have default values. In
every other case, as far as I know, x = x || y also describes what's
happening. But the expansion which describes *every* case is x || x =
y.

One other case (a very similar one) in which it matters is this:

class C
def x; @x || 5; end
def x=(v); puts "assigning @x=#{v}"; @x = v; end
end

c = C.new
c.x ||= 3 # no effect
p c.x # 5
c.x = 2 # assigning @x=2
p c.x # 2
 
R

Rick DeNatale

The only time this matters is with hashes that have default values. In
every other case, as far as I know, x = x || y also describes what's
happening.

Well here's another:

class Foo

attr_writer :x

def x
@x || 1 # !> instance variable @x not initialized
end

def inspect
"Foo(#{@x})" # !> instance variable @x not initialized
end
end

f = Foo.new
f.x # => 1
f # => Foo()
f.x ||= 2
f.x # => 1
f # => Foo()
f.x || f.x = 2
f.x # => 1
f # => Foo()
f.x = f.x || 2
f.x # => 1
f # => Foo(1)
 
R

Robert Dober

David A. Black wrote:



One other case (a very similar one) in which it matters is this:

class C
def x; @x || 5; end
def x=(v); puts "assigning @x=#{v}"; @x = v; end
end

c = C.new
c.x ||= 3 # no effect
p c.x # 5
c.x = 2 # assigning @x=2
p c.x # 2
Hmm I am not sure I believe you rushed your example a little bit

c.x = c.x || a
and
c.x || c.x = a
seem to me having the same effect.

I only came up with a perverse example to show the difference
class C
count = 0
def x; true end
define_method :x= do |_|
count += 1
@x = count
end
end

c = C.new
c.x || c.x = 42
p c
c.x = c.x || 42
p c
c.x ||= 42
p c

Cheers
Robert
 
D

David A. Black

Hi --

Hmm I am not sure I believe you rushed your example a little bit

c.x = c.x || a
and
c.x || c.x = a
seem to me having the same effect.

I don't think so:

irb(main):017:0> c = C.new
=> #<C:0x87d0c>
irb(main):018:0> c.x || c.x = 1 # 5 || c.x = 1 => 5
=> 5
irb(main):019:0> c.instance_eval { @x }
=> nil
irb(main):020:0> c.x = c.x || 1 # c.x = 5 || 1 => c.x = 5
assigning @x=5
=> 5
irb(main):021:0> c.instance_eval { @x }
=> 5


David

--
Rails training from David A. Black and Ruby Power and Light:
ADVANCING WITH RAILS April 14-17 New York City
INTRO TO RAILS June 9-12 Berlin
ADVANCING WITH RAILS June 16-19 Berlin
See http://www.rubypal.com for details and updates!
 
R

Robert Dober

Hi --


I don't think so:

irb(main):017:0> c = C.new
=> #<C:0x87d0c>
irb(main):018:0> c.x || c.x = 1 # 5 || c.x = 1 => 5
=> 5
irb(main):019:0> c.instance_eval { @x }
that is true but that point was difficult to see, and I preferred an
example which shows the difference from the "normal" object interface
although my code is of course perverted.
 
T

Todd Benson

Note though that "logistical" != "logical" - two quite different pairs of
shoes. :)

Cheers

robert

That's being a little nitpicky. I think either word works in this
case, but I understand what you meant :)

Todd
 
R

Robert Klemme

That's being a little nitpicky.
Absolutely!

I think either word works in this
case, but I understand what you meant :)

If by "works" you mean "can be understood" then, yes. If you say that
the word can be placed there from a language point of view, also yes. I
do believe though that "logistically" is semantically misplaced here. :))

Cheers

robert
 
R

Robert Dober

Hi --




that is true but that point was difficult to see, and I preferred an
example which shows the difference from the "normal" object interface
although my code is of course perverted.
and one cannot see the problem through the object interface either :(
In an attempt to make things clear enough I will take Joel's code again:

class << C = Class::new
def x; @x || 5 end
def get_x; @x end
def x= v; @x=v end
end

C.get_x --> nil
C.x ||= 42
C.get_x --> nil
C.x || C.x = 42
C.get_x --> nil
C.x = C.x || 42
C.get_x --> 5

Hurray I guess I finally got it.
Thx for the enlightenment.

Cheers
Robert
 
B

Brian Adkins

Strictly speaking, it isn't shorthand for either, since there are
cases where the expansion will fail but ||= won't because x isn't
initialized. However, discounting that, the expansion is:

x || x = y

The only time this matters is with hashes that have default values. In
every other case, as far as I know, x = x || y also describes what's
happening. But the expansion which describes *every* case is x || x =
y.

I wrote a blog post about this recently:http://dablog.rubypal.com/2008/3/25/a-short-circuit-edge-case
(I changed || to or for some reason, which screws up the precedence,
but I inserted corrections later.)

Interesting - nice blog post. That is surprising, inconsistent and
unfortunate :(
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top