The ||= assignment operator

It was my understanding that the ||= assignment operator assigned the
value
on the right-hand side if and only if the left hand side did not already
have a value:

irb(main):001:0> x = true
=> true
irb(main):002:0> x ||= “ruby”
=> true
irb(main):003:0> x
=> true
And, likewise, with nil:

irb(main):014:0> x = nil
=> nil
irb(main):015:0> x ||= “ruby”
=> “ruby”
irb(main):016:0> x
=> “ruby”
However, I do not understand this behavior:

irb(main):019:0> x = false
=> false
irb(main):020:0> x ||= “ruby”
=> “ruby”
irb(main):021:0> x
=> “ruby”

We know that false != nil, and yet the ||= will assign if the left hand
side
is false?

regards,
Matt

On Fri, Apr 4, 2008 at 2:11 PM, Belorion [email protected] wrote:

And, likewise, with nil:
=> false
Matt
The operators are working with a three-valued logic. In a comparison,
a FalseClass object or a NilClass object will be logistically false.

Todd

On Fri, Apr 4, 2008 at 1:11 PM, Belorion [email protected] wrote:

=> true
irb(main):019:0> x = false

regards,
Matt

Nope ||= will assign if nil or false.


“Hey brother Christian with your high and mighty errand, Your actions
speak
so loud, I can’t hear a word you’re saying.”

-Greg Graffin (Bad Religion)

Thanks all, that clears up my understanding. I hadn’t thought of it as
x =
x || “ruby” (even thoughI knew that x += 1 is the same as x = x + 1) and
that in that expanded case, x evaluates, logistically, to false if nil
or
false.

Matt

On Fri, Apr 4, 2008 at 2:41 PM, Belorion [email protected] wrote:

Thanks all, that clears up my understanding. I hadn’t thought of it as x =
x || “ruby” (even thoughI knew that x += 1 is the same as x = x + 1) and
that in that expanded case, x evaluates, logistically, to false if nil or
false.

For conditional expressions. Here’s something that may catch you off
guard…

irb(main):001:0> nil || false
=> false
irb(main):001:0> false || nil
=> nil

Todd

On Apr 4, 1:30 pm, Paul M. [email protected] wrote:

already having a value". If you do this, then you can see why your
Hope that this helps.
It’s better to think of x ||= “ruby” as x || x = “ruby”.


h = Hash.new(‘default value’)

h[:test] ||= ‘assigned value’
h # => {}

same as:

h[:test] || h[:test] = ‘assigned value’
h # => {}

not:

h[:test] = h[:test] || ‘assigned value’
h # => {:test=>“default value”}

Chris

On 4 Apr 2008, at 20:11, Belorion wrote:

It was my understanding that the ||= assignment operator assigned
the value
on the right-hand side if and only if the left hand side did not
already
have a value:

It’s probably better to think of x ||= “ruby” as being short hand for
x = x || “ruby” (which it effectively is) instead of “assign if not
already having a value”. If you do this, then you can see why your
last example behaves like it does.

Don’t forget that there are other similar operators like +=, -= and
&&= and they all follow the same pattern:

x ?= y
x = x ? y

Where ? is one of -, +, && or ||.

Hope that this helps.

From: Chris S. [mailto:[email protected]]

It’s better to think of x ||= “ruby” as x || x = “ruby”.

h = Hash.new(‘default value’)

h[:test] ||= ‘assigned value’

h # => {}

# same as:

h[:test] || h[:test] = ‘assigned value’

h # => {}

# not:

h[:test] = h[:test] || ‘assigned value’

h # => {:test=>“default value”}

i’d say that’s a bug in design (unless x+=1 is now x+x=1 :wink:

kind regards -botp

On this topic, am I the only one who would really like to see a
dedicated “defaulting operator” in Ruby? Something that actually has
the semantics which a lot of people mistakenly assume for ||=, i.e.
“assign if and only if nil”? I think Perl6 uses the //= operator for
this. This is such a subtle gotcha. I’ve seen a lot of code that was
potentially buggy because it didn’t account for the fact that the
‘false’ value would be handled incorrectly.

On Apr 4, 2008, at 8:53 PM, Avdi G. wrote:

On this topic, am I the only one who would really like to see a
dedicated “defaulting operator” in Ruby? Something that actually has
the semantics which a lot of people mistakenly assume for ||=, i.e.
“assign if and only if nil”? I think Perl6 uses the //= operator for
this. This is such a subtle gotcha. I’ve seen a lot of code that was
potentially buggy because it didn’t account for the fact that the
‘false’ value would be handled incorrectly.


Avdi

This would be great, but you would need both a // and //= operator.
Consider this:

@my_web_page_title = @page_name || “d’oh! you forgot to name your page”

You would want to rewrite this as:

@my_web_page_title = @page_name // “d’oh! you forgot to name your page”

It would seem that adding these operators has a low potential to
introduce bugs into working code and, as you point out, there are
subtleties WRT the ||= idiom. Moving it from idiom to first-class
operator might clarify those subtleties.

Peña, Botp wrote:

From: Chris S. [mailto:[email protected]]

It’s better to think of x ||= “ruby” as x || x = “ruby”.

h = Hash.new(‘default value’)

h[:test] ||= ‘assigned value’

h # => {}

# same as:

h[:test] || h[:test] = ‘assigned value’

h # => {}

# not:

h[:test] = h[:test] || ‘assigned value’

h # => {:test=>“default value”}

i’d say that’s a bug in design (unless x+=1 is now x+x=1 :wink:

kind regards -botp

Not at all. Rather, this is just a subtle misunderstanding of how hash
is implemented. Consider the following:

h = Hash.new
=> {}

h[:test] ||= ‘testing without default’
=> “testing without default”

h
=> {:test=>“testing without default”}

h = Hash.new(‘default value’)
=> {}

h[:test] ||= ‘testing with default’
=> “default value”

h
=> {}

The only reason that Chris’ example behaves like “x || x = stuff” is
because he’s defined a default value for the hash. If you set a default
value, than you’ll never have a keyed value be empty (i.e. nil).
Consider further:

h = Hash.new
=> {}

puts ‘empty’ unless h[:test]
empty
=> nil

h = Hash.new(‘default value’)
=> {}

puts ‘empty’ unless h[:test]
=> nil

I think the confusion is that, in Chris’ example, there’s no assignment,
so the hash only holds the default value temporarily (i.e. just long
enough to not evaluate to nil or false).

On Apr 5, 12:46 am, Joshua B. [email protected] wrote:

# same as:

Not at all. Rather, this is just a subtle misunderstanding of how hash
is implemented.

The only reason that Chris’ example behaves like “x || x = stuff” is
because he’s defined a default value for the hash. If you set a default
value, than you’ll never have a keyed value be empty (i.e. nil).
Consider further:

I think the confusion is that, in Chris’ example, there’s no assignment,
so the hash only holds the default value temporarily (i.e. just long
enough to not evaluate to nil or false).

Posted viahttp://www.ruby-forum.com/.

There was a long thread about this some time ago, and I’m too tired to
search for it now. In the end, it came down a difference of opinion.

Some people say this violates their expectations because they’re told
that var op= value translates to var = var op value always.

Other people say this is expected because var ||= value really means
var = value unless var and everybody should know that.

Personally, I am in the former camp. I think of the latter as an
optimization that works in many places, but optimizations are usually
a form of cheating and cheaters eventually get caught. In Ruby, this
cheater gets caught in the web of deceit centered around hashes with
default values.

Note that hash_with_default_value[key] ||= val is the only place
where this is even an issue.

From: Joshua B. [mailto:[email protected]]

Not at all. Rather, this is just a subtle misunderstanding of

how hash is implemented. Consider the following:

>> h = Hash.new

=> {}

>> h[:test] ||= ‘testing without default’

=> “testing without default”

>> h

=> {:test=>“testing without default”}

>> h = Hash.new(‘default value’)

=> {}

>> h[:test] ||= ‘testing with default’

=> “default value”

>> h

=> {}

The only reason that Chris’ example behaves like “x || x = stuff” is

because he’s defined a default value for the hash. If you set

a default value, than you’ll never have a keyed value be empty

(i.e. nil). Consider further:

>> h = Hash.new

=> {}

>> puts ‘empty’ unless h[:test]

empty

=> nil

>> h = Hash.new(‘default value’)

=> {}

>> puts ‘empty’ unless h[:test]

=> nil

my question is simple,

given,

h = Hash.new(‘default value’)
#=> {}

why is

h[:test] ||= ‘this is alternative’
#=> “default value”
h
#=> {}

different from

h[:test] = h[:test] || ‘this is alternative’
#=> “default value”
h
#=> {:test=>“default value”}

??

That is not a nice surprise, imho; and the (syntax) sugar is not sweet
:slight_smile:

kind regards -botp

Hi –

On Sat, 5 Apr 2008, Avdi G. wrote:

On this topic, am I the only one who would really like to see a
dedicated “defaulting operator” in Ruby? Something that actually has
the semantics which a lot of people mistakenly assume for ||=, i.e.
“assign if and only if nil”? I think Perl6 uses the //= operator for
this. This is such a subtle gotcha. I’ve seen a lot of code that was
potentially buggy because it didn’t account for the fact that the
‘false’ value would be handled incorrectly.

The false value isn’t handled incorrectly, though. The test is for
boolean falseness, and both nil and false always pass that test. If
you need x to be a certain value (nil or any other), you should test
for exactly that value.

Also, it’s not exactly that the lhs of ||= is nil. ||= will allow
uninitialized local variables, which are not nil:

irb(main):003:0> a ||= 1
=> 1
irb(main):004:0> b || b = 1
NameError: undefined local variable or method `b’ for main:Object
from (irb):4

So we’d be getting into a thing with “uninitialized or nil, but not
false” which seems very use-case specific to me. I’d rather let the
boolean significance just do its thing.

David

HI –

On Sat, 5 Apr 2008, Joshua B. wrote:

# same as:

kind regards -botp

h = Hash.new(‘default value’)
=> {}

h[:test] ||= ‘testing with default’
=> “default value”

h
=> {}

The only reason that Chris’ example behaves like “x || x = stuff” is
because he’s defined a default value for the hash. If you set a default
value, than you’ll never have a keyed value be empty (i.e. nil).

The only expansion that accounts for all cases of the ||= operator is
x || x = stuff. If it were actually x = x || stuff, then this:

irb(main):005:0> h = Hash.new(1)
=> {}
irb(main):006:0> h[:x] = h[:x] || 2
=> 1
irb(main):007:0> h
=> {:x=>1}

would behave the same as this:

irb(main):008:0> h[:y] ||= 2
=> 1
irb(main):009:0> h
=> {:x=>1}

but it doesn’t. But ||= does behave like this:

irb(main):010:0> h[:z] || h[:z] = 2
=> 1
irb(main):011:0> h
=> {:x=>1}

In other words, x ||= y == x || x = y, or something :slight_smile:

I personally would like to see it act like x = x || y, though I think
hash defaults are the only case where the difference actually makes a
difference.

David

On Sat, Apr 5, 2008 at 10:25 AM, Peña, Botp [email protected] wrote:

>> h = Hash.new(‘default value’)

=> {}

given,
#=> {}
That is not a nice surprise, imho; and the (syntax) sugar is not sweet :slight_smile:

kind regards -botp

I respectfully disagree, this is very well defined behavior, I
partially blame the list which very often explained to newbies that

@x ||= value

assignes value to @x when it was not defined before. It is sad that
things are incorrectly explained, that is all.
Furthermore things are simple

(1) lval ||= rval is lval = lval || rval
(2) nil || x = x
(3) false || x = x
(4) non initialized ivars evaluate to nil

once one accepts these basic rules of the language there is no surprise.
I like the syntactic sugar but to use a recently used quote “DE
GVSTIBVS NON DISPVTANDVM EST”

Cheers
Robert


http://ruby-smalltalk.blogspot.com/


Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

On Sat, Apr 5, 2008 at 2:40 PM, David A. Black [email protected]
wrote:

I think you mean:

lval || lval = rval

(See the hash default case which flushes this out.)
Wow David, as they say “A little knowledge is a dangerous thing”, well
as I said ignorants like me teaching nonsense :frowning:

Thx for correcting me David.

Cheers
Robert

ADVANCING WITH RAILS June 16-19 Berlin
See http://www.rubypal.com for details and updates!


http://ruby-smalltalk.blogspot.com/


Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

On Sat, Apr 5, 2008 at 6:13 AM, David A. Black

The false value isn’t handled incorrectly, though.

When I wrote “handled incorrectly”, I didn’t mean that Ruby handles it
incorrectly; I meant that I’ve seen a great deal of code people had
written which was incorrect in the face of explicit ‘false’ values
because of this very common misunderstanding of ||=.

The test is for
boolean falseness, and both nil and false always pass that test. If
you need x to be a certain value (nil or any other), you should test
for exactly that value.

I agree. Which is why I often use something like
if x.nil? then x = y end
which isn’t nearly as concise and expressive as x ||= y. It could be
somewhat shortened to:
x.nil? && x = y
but I don’t find that particularly readable. In any case, neither
of them conveniently handles the case where x is undefined as well as
the case where x is nil, the way ||= does, as you note below:

Also, it’s not exactly that the lhs of ||= is nil. ||= will allow
uninitialized local variables, which are not nil:
[…]
So we’d be getting into a thing with “uninitialized or nil, but not
false” which seems very use-case specific to me.

The core of my argument is that this idiom isn’t rare or use-case
specific at all. is, in my experience of both writing and reading Ruby
code, an extremely common pattern. Being able to concisely and
unambiguously say “after this line, x (or h[:x]) is guaranteed to be
initialized and non-nil, either by previous assignment or by the
specified default” is something I see a need for every working day.
And because it’s such a common need, and because ||= seems so
deceptively close to fulfilling it, I have seen many, many examples of
code that was subtly incorrect because it used ||=. Ruby is a
language that often offers sugar for common idioms, and this is a very
common idiom.


Avdi

Hi –

On Sat, 5 Apr 2008, Robert D. wrote:

Furthermore things are simple

(1) lval ||= rval is lval = lval || rval

I think you mean:

lval || lval = rval

(See the hash default case which flushes this out.)

David

On Apr 5, 8:40 am, “David A. Black” [email protected] wrote:

Hi –

On Sat, 5 Apr 2008, Robert D. wrote:

Furthermore things are simple

(1) lval ||= rval is lval = lval || rval

I think you mean:

lval || lval = rval

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.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs