Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between a || a = b and a = a || b in ruby?

Tags:

ruby

Can anyone put light on this expression. Seems like both are same but they are not.

a || a = b or a ||= b

and

a = a || b

if

a = 4 and b = 6, output is always 4

This always confuse and misconcept me. Can someone please explain it?

like image 420
Chitrank Samaiya Avatar asked May 29 '15 08:05

Chitrank Samaiya


2 Answers

a || a = b

looks for a if a is truthy, returns a, otherwise a = b is done i.e. you assign b's value to a.

a = a || b

This is an assignment operation. Here you are assigning value to a irrespective of what value it holds. So a equals a || b. In second part of the statement you are looking for a. If its value is truthy you are assigning it back to a itself, else you are assigning b's value to a.

TL;DR

a = a || b is assigning a value (depending on condition) to a irrespective of what value it holds.

a ||= b return a if already present, else does a = b

Explaining with example:

You can think of a || a = b as a || (a = b). Now lets assume a = 4 and b = 6.

Since by order of precedence, this is an OR operation and since order of operations for OR is left to right we start with first a:

 # lets call this Fig. 1
      a || (a = b)
      ^
      |
      .
   (here)

This a has value 4, which is a truthy value. Therefore the evaluation stops then and there and 4 is returned. ( Why? Hint: true || anything = true)

Now lets assume a = nil and b = 6. We start again from same place (Fig. 1). Since a is nil which is falsely in Ruby, we move to the right side of the OR operation, i.e. a = b

 # lets call this Fig. 2
      a || (a = b)
              ^
              |
              .
           (here)

As this is an assignment operation, it will get executed and we will end up assigning 6 to a.

Coming back to a = a || b. You can think this as a = (a || b). Clearly by order of precedence its an assignment operation. Since order of operations for assignment is right to left, (a || b) is evaluated first.

 # lets call this Fig. 3
      a = (a || b)
             ^
             |
             .
          (here)

If a = 4 and b = 6, a || b will return 4 (as discussed above). Else if a = nil and b = 6, a || b will return 6.

Now whatever value is returned from this || operation is getting assigned to the first a.

 # lets call this Fig. 4
      a = (a || b)
      ^
      |
      .
    (here)
like image 174
shivam Avatar answered Sep 18 '22 12:09

shivam


A common misconception is that :

a ||= b is equivalent to a = a || b, but it behaves like a || a = b

In a = a || b, a is set to something by the statement on every run, whereas with a || a = b, a is only set if a is logically false (i.e. if it's nil or false) because || is 'short circuiting'.

Let me keep that simple :

That is, if the left hand side of the || comparison is true, there's no need to check the right hand side.

more reference RubyInside

like image 42
Tharif Avatar answered Sep 18 '22 12:09

Tharif