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

Viewed 153167

What does the following code mean in Ruby?

||=

Does it have any meaning or reason for the syntax?

23 Answers

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.

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

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

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.

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.

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.

Related