collimarco
collimarco

Reputation: 35379

What does ||= (or-equals) mean in Ruby?

What does the following code mean in Ruby?

||=

Does it have any meaning or reason for the syntax?

Upvotes: 462

Views: 196532

Answers (23)

Matteo
Matteo

Reputation: 1136

I think of it as an is or operator. a ||= b is evaluated as If a is equal to anything other than nil, then use the value of a. If a evaluates to nil then use the value of b.

In other words, it is the same as if a == NOT nil, then a, else b.

Upvotes: 0

Jörg W Mittag
Jörg W Mittag

Reputation: 369420

This question has been discussed so often on the Ruby mailing-lists and Ruby blogs that there are now even threads on the Ruby mailing-list whose only purpose is to collect links to all the other threads on the Ruby mailing-list that discuss this issue.

Here's one: The definitive list of ||= (OR Equal) threads and pages

If you really want to know what is going on, take a look at Section 11.4.2.3 "Abbreviated assignments" of the Ruby Language Draft Specification.

As a first approximation,

a ||= b

is equivalent to

a || a = b

and not equivalent to

a = a || b

However, that is only a first approximation, especially if a is undefined. The semantics also differ depending on whether it is a simple variable assignment, a method assignment or an indexing assignment:

a    ||= b
a.c  ||= b
a[c] ||= b

are all treated differently.

Upvotes: 181

Steve Bennett
Steve Bennett

Reputation: 125995

a ||= b is a conditional assignment operator. It means:

  • if a is undefined or falsey, then evaluate b and set a to the result.
  • Otherwise (if a is defined and evaluates to truthy), then b is not evaluated, and no assignment takes place.

For example:

a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0

foo = false # => false
foo ||= true # => true
foo ||= false # => true

Confusingly, it looks similar to other assignment operators (such as +=), but behaves differently.

  • a += b translates to a = a + b
  • a ||= b roughly translates to a || a = b

It is a near-shorthand for a || a = b. The difference is that, when a is undefined, a || a = b would raise NameError, whereas a ||= b sets a to b. This distinction is unimportant if a and b are both local variables, but is significant if either is a getter/setter method of a class.

Further reading:

Upvotes: 767

z atef
z atef

Reputation: 7679

If X does NOT have a value, it will be assigned the value of Y. Else, it will preserve it's original value, 5 in this example:

irb(main):020:0> x = 5
=> 5
irb(main):021:0> y = 10
=> 10
irb(main):022:0> x ||= y
=> 5

# Now set x to nil. 

irb(main):025:0> x = nil
=> nil
irb(main):026:0> x ||= y
=> 10

Upvotes: 10

SHUBHAM SHARMA
SHUBHAM SHARMA

Reputation: 31

a ||= b

Signifies if any value is present in 'a' and you dont want to alter it the keep using that value, else if 'a' doesnt have any value, use value of 'b'.

Simple words, if left hand side if not null, point to existing value, else point to value at right side.

Upvotes: 3

nPcomp
nPcomp

Reputation: 9833

Basically,


x ||= y means

if x has any value leave it alone and do not change the value, otherwise set x to y

Upvotes: 20

tessie
tessie

Reputation: 1034

As a common misconception, a ||= b is not equivalent to a = a || b, but it behaves like a || a = b.

But here comes a tricky case. If a is not defined, a || a = 42 raises NameError, while a ||= 42 returns 42. So, they don't seem to be equivalent expressions.

Upvotes: 1

Sunda
Sunda

Reputation: 227

||= is a conditional assignment operator

  x ||= y

is equivalent to

  x = x || y

or alternatively

if defined?(x) and x
    x = x
else 
    x = y
end

Upvotes: 4

Ymox
Ymox

Reputation: 329

a ||= b is the same as saying a = b if a.nil? or a = b unless a

But do all 3 options show the same performance? With Ruby 2.5.1 this

1000000.times do
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
end

takes 0.099 Seconds on my PC, while

1000000.times do
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
end

takes 0.062 Seconds. That's almost 40% faster.

and then we also have:

1000000.times do
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
end

which takes 0.166 Seconds.

Not that this will make a significant performance impact in general, but if you do need that last bit of optimization, then consider this result. By the way: a = 1 unless a is easier to read for the novice, it is self-explanatory.

Note 1: reason for repeating the assignment line multiple times is to reduce the overhead of the loop on the time measured.

Note 2: The results are similar if I do a=nil nil before each assignment.

Upvotes: -3

Max Rogers
Max Rogers

Reputation: 914

This is the default assignment notation

for example: x ||= 1
this will check to see if x is nil or not. If x is indeed nil it will then assign it that new value (1 in our example)

more explicit:
if x == nil
x = 1
end

Upvotes: 2

Charlie Wood
Charlie Wood

Reputation: 111

||= is called a conditional assignment operator.

It basically works as = but with the exception that if a variable has already been assigned it will do nothing.

First example:

x ||= 10

Second example:

x = 20
x ||= 10

In the first example x is now equal to 10. However, in the second example x is already defined as 20. So the conditional operator has no effect. x is still 20 after running x ||= 10.

Upvotes: 4

siva krishna reddy
siva krishna reddy

Reputation: 19

b = 5
a ||= b

This translates to:

a = a || b

which will be

a = nil || 5

so finally

a = 5

Now if you call this again:

a ||= b
a = a || b
a = 5 || 5
a = 5

b = 6

Now if you call this again:

a ||= b
a = a || b
a = 5 || 6
a = 5 

If you observe, b value will not be assigned to a. a will still have 5.

Its a Memoization Pattern that is being used in Ruby to speed up accessors.

def users
  @users ||= User.all
end

This basically translates to:

@users = @users || User.all

So you will make a call to database for the first time you call this method.

Future calls to this method will just return the value of @users instance variable.

Upvotes: 1

frediy
frediy

Reputation: 1766

Concise and complete answer

a ||= b

evaluates the same way as each of the following lines

a || a = b
a ? a : a = b
if a then a else a = b end

-

On the other hand,

a = a || b

evaluates the same way as each of the following lines

a = a ? a : b
if a then a = a else a = b end

-

Edit: As AJedi32 pointed out in the comments, this only holds true if: 1. a is a defined variable. 2. Evaluating a one time and two times does not result in a difference in program or system state.

Upvotes: 35

Pankhuri
Pankhuri

Reputation: 978

Suppose a = 2 and b = 3

THEN, a ||= b will be resulted to a's value i.e. 2.

As when a evaluates to some value not resulted to false or nil.. That's why it ll not evaluate b's value.

Now Suppose a = nil and b = 3.

Then a ||= b will be resulted to 3 i.e. b's value.

As it first try to evaluates a's value which resulted to nil.. so it evaluated b's value.

The best example used in ror app is :

#To get currently logged in iser
def current_user
  @current_user ||= User.find_by_id(session[:user_id])
end

# Make current_user available in templates as a helper
helper_method :current_user

Where, User.find_by_id(session[:user_id]) is fired if and only if @current_user is not initialized before.

Upvotes: 3

0r4cl3
0r4cl3

Reputation: 132

unless x x = y end

unless x has a value (it's not nil or false), set it equal to y

is equivalent to

x ||= y

Upvotes: 3

Luca Guidi
Luca Guidi

Reputation: 1211

Please also remember that ||= isn't an atomic operation and so, it isn't thread safe. As rule of thumb, don't use it for class methods.

Upvotes: 2

vidang
vidang

Reputation: 1771

In short, a||=b means: If a is undefined, nil or false, assign b to a. Otherwise, keep a intact.

Upvotes: 33

Ajedi32
Ajedi32

Reputation: 48318

To be precise, a ||= b means "if a is undefined or falsy (false or nil), set a to b and evaluate to (i.e. return) b, otherwise evaluate to a".

Others often try to illustrate this by saying that a ||= b is equivalent to a || a = b or a = a || b. These equivalencies can be helpful for understanding the concept, but be aware that they are not accurate under all conditions. Allow me to explain:

  • a ||= ba || a = b?

    The behavior of these statements differs when a is an undefined local variable. In that case, a ||= b will set a to b (and evaluate to b), whereas a || a = b will raise NameError: undefined local variable or method 'a' for main:Object.

  • a ||= ba = a || b?

    The equivalency of these statements are often assumed, since a similar equivalence is true for other abbreviated assignment operators (i.e. +=,-=,*=,/=,%=,**=,&=,|=,^=,<<=, and >>=). However, for ||= the behavior of these statements may differ when a= is a method on an object and a is truthy. In that case, a ||= b will do nothing (other than evaluate to a), whereas a = a || b will call a=(a) on a's receiver. As others have pointed out, this can make a difference when calling a=a has side effects, such as adding keys to a hash.

  • a ||= ba = b unless a??

    The behavior of these statements differs only in what they evaluate to when a is truthy. In that case, a = b unless a will evaluate to nil (though a will still not be set, as expected), whereas a ||= b will evaluate to a.

  • a ||= bdefined?(a) ? (a || a = b) : (a = b)????

    Still no. These statements can differ when a method_missing method exists which returns a truthy value for a. In this case, a ||= b will evaluate to whatever method_missing returns, and not attempt to set a, whereas defined?(a) ? (a || a = b) : (a = b) will set a to b and evaluate to b.

Okay, okay, so what is a ||= b equivalent to? Is there a way to express this in Ruby?

Well, assuming that I'm not overlooking anything, I believe a ||= b is functionally equivalent to... (drumroll)

begin
  a = nil if false
  a || a = b
end

Hold on! Isn't that just the first example with a noop before it? Well, not quite. Remember how I said before that a ||= b is only not equivalent to a || a = b when a is an undefined local variable? Well, a = nil if false ensures that a is never undefined, even though that line is never executed. Local variables in Ruby are lexically scoped.

Upvotes: 9

gotnull
gotnull

Reputation: 27214

irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1

Because a was already set to 1

irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2

Because a was nil

Upvotes: 0

mukh007
mukh007

Reputation: 339

It's like lazy instantiation. If the variable is already defined it will take that value instead of creating the value again.

Upvotes: 2

RileyE
RileyE

Reputation: 11074

a ||= b

is equivalent to

a || a = b

and not

a = a || b

because of the situation where you define a hash with a default (the hash will return the default for any undefined keys)

a = Hash.new(true) #Which is: {}

if you use:

a[10] ||= 10 #same as a[10] || a[10] = 10

a is still:

{}

but when you write it like so:

a[10] = a[10] || 10

a becomes:

{10 => true}

because you've assigned the value of itself at key 10, which defaults to true, so now the hash is defined for the key 10, rather than never performing the assignment in the first place.

Upvotes: 2

Kiattisak Anoochitarom
Kiattisak Anoochitarom

Reputation: 2157

x ||= y

is

x || x = y

"if x is false or undefined, then x point to y"

Upvotes: 8

Jamie Rumbelow
Jamie Rumbelow

Reputation: 5095

It means or-equals to. It checks to see if the value on the left is defined, then use that. If it's not, use the value on the right. You can use it in Rails to cache instance variables in models.

A quick Rails-based example, where we create a function to fetch the currently logged in user:

class User > ActiveRecord::Base

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end

end

It checks to see if the @current_user instance variable is set. If it is, it will return it, thereby saving a database call. If it's not set however, we make the call and then set the @current_user variable to that. It's a really simple caching technique but is great for when you're fetching the same instance variable across the application multiple times.

Upvotes: 21

Related Questions