Conditional Assignment Operator in Ruby

josh pann
3 min readJan 5, 2017

--

On wednesday, Flatiron School gave me a challenging lab to solve. It was the first in a series of labs using cookies to create a unique session for the user. The instructions seemed deceptively simple. The implementation was far from easy (in part because it did not follow RESTful conventions, but that is a topic for a different post).

A Short Story of our App.

We wanted our app to have only one page on it with a route of ‘/’. This URL should respond to a get request by rendering a simple form where a user can submit a product name as a string to add it their unique cart. This URL should also respond to a post request to perform the adding action. Our cart needs to initialize as an empty array if it doesn’t exist and then have itself be accessible to the form to so product names can be added to it. I accomplished this by creating a method with the handy “Conditional Assignment Operator ||=” in my Application Controller. For example:

def cart
@cart = session[:cart] ||= []
end

Conditional Assignment Operator || = []:

Here is a a simplified use of the conditional assignment operator to illustrate the definition:

a ||= b

If a is false, nil or undefined, then evaluate b and set a to the result. This seems to imply that if a exists, set a equal to itself. If a does not exist,

a = a || b

This works if a and b are undefined local variables:

a = nil
b = 20
a ||= b
a # => 20

However, this picture becomes a bit more complicated if they are defined or if we are using more complex data structures like arrays and hashes.

h = {}

def h.[]=(k, v)
puts "Setting value of hash key #{k} to #{v}"
end
# 1. The a = a || b approach
h[:y] = h[:y] || 10
h[:y] = h[:y] || 20
# 2. The ||= approach
h[:x] ||= 10
h[:x] ||= 20

Output:Method 1:
Setting value of hash key y to 10
Setting value of hash key y to 10
Method 2:
Setting value of hash key x to 10

These seem to be the same at first glance. Both ways set the value of a hash key to 10. But there is one critical difference. Our code block executes twice using Method 1, but only once using method 2. This means there is more to the conditional assignment operator than what there appears to be. Something about the way this operator is written executes the block of code only once certain conditions are met. Lets expand this operator to see if we can establish what is going on.

h = {}

def h.[]=(k, v)
puts "Setting value of hash key #{k} to #{v}"
super
end

h[:x] ||= 10
def conditional_assignment_operator(object)
if h[:x]
h[:x]
else
h[:x] = object
end
h[:x]
end

The conditional assignment operator evaluates h[:x] for existence. I have reproduced the check below using in an IRB session with some edits for clarity.

2.3.0 :006 > h = {}=> {}2.3.0 :007 > def h.[]=(k, v)
puts "Setting value of hash key #{k} to #{v}"
end
2.3.0 :010 > h[:x]=> nil

On our first pass h[:x] evaluates to nil. Thus, the block in the if statement is not evaluated and our program evaluates the block located in the else statement. It will assign the object to what is passed into the conditional assignment operator as the value of our hash key. Then our operator will return the value of our hash key. Lets go head and check this.

2.3.0 :007 > h[:x] ||= 10Setting hash key x with 10=> 10

Now our key has a value pair. The condition will evaluate to true and the code block within the if portion of our conditional will execute returning the value of our key.

2.3.0 :008 > h[:x] ||= 10=> 10

The key insight is the setter method is only being called once. This is true empirically because we included a puts statement inside of our setter method — puts “Setting value of hash key #{k} to #{v}". This is not being printed to the terminal on the second pass.

--

--