15

Could some one explain to me the meaning of the following Ruby code? (I saw this code snippet in one guy's project):

car ||= (method_1 || method_2 || method_3 || method_4)

What is the difference between the above code and the following code?

car = method_1 || method_2 || method_3 || method_4

----------update--------------

Ok, I got the meaning of ||= operator after read @Dave's explanation, my next question is if both method_2, method_3 and method_4 return a value, which one's value will be assigned to car? (I suppose car is nil initially)

Naftali
  • 144,921
  • 39
  • 244
  • 303
Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • 1
    http://stackoverflow.com/questions/995593/what-does-mean-in-ruby – Josh Lee Dec 14 '11 at 15:20
  • 1
    Duplicate: [What does `||=` mean in Ruby?](http://StackOverflow.Com/q/995593/), [What does `||=` mean in Ruby?](http://StackOverflow.Com/q/3800957/), [what is `||=` in ruby?](http://StackOverflow.Com/q/3945711/), [Double Pipe Symbols in Ruby Variable Assignment?](http://StackOverflow.Com/q/4500375/), [What does the “`||=`” operand stand for in ruby](http://StackOverflow.Com/q/5124930/), [what does a `||=` mean in Ruby language?](http://StackOverflow.Com/q/5230162/), [Is the ruby operator `||=` intelligent?](http://StackOverflow.Com/q/2989862/), … – Jörg W Mittag Dec 14 '11 at 15:37
  • … [What does `||=` mean?](http://StackOverflow.Com/q/7556902/), [What does “`||=`” do in Ruby 1.9.2?](http://StackOverflow.Com/q/7714803/), and probably many others as well. See also [The definitive list of `||=` (OR Equal) threads and pages](http://Ruby-Forum.Com/topic/151660/). – Jörg W Mittag Dec 14 '11 at 15:37
  • Regarding your edit: `||` and `&&` short circuit, which in case of `||` means evaluation stops as soon as a truthy (not `nil` or `false`) value is encountered, whereas `&&` stops as soon as it finds a falsey value. – Michael Kohl Dec 14 '11 at 16:19

7 Answers7

11

It's an assignment operator for 'Conditional Assignment'

See here -> http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Operators

Conditional assignment:

 x = find_something() #=>nil
 x ||= "default"      #=>"default" : value of x will be replaced with "default", but only if x is nil or false
 x ||= "other"        #=>"default" : value of x is not replaced if it already is other than nil or false

Operator ||= is a shorthand form of the expression:

x = x || "default" 

EDIT:

After seeing OP's edit, the example is just an extension of this, meaning:

car = method_1 || method_2 || method_3 || method_4

Will assign the first non-nil or non-false return value of method_1, method_2, method_3, method_4 (in that order) to car or it'll retain its old value.

cbmanica
  • 3,502
  • 7
  • 36
  • 54
Dave
  • 6,905
  • 2
  • 32
  • 35
  • 1
    Your explanation is a bit different from others, but I kind like your explanation because you have pointed out the key point of using this operator (conditional assignment). Though it is better if you can also mention x||= Y is equal to x=x||y – Leem.fin Dec 14 '11 at 14:51
  • Please check my update, I have a new question regards to the operator. – Leem.fin Dec 14 '11 at 15:00
  • Hey, glad I've helped - I've edited my answer to include a little extra - hopefully it'll address your first comment and your questions update. – Dave Dec 14 '11 at 15:00
  • 1
    @ Dave, have you checked my update in my post, I have a new question which yields after read your answer. In general, I would like to know if several methods return value, which one's value will be assigned to the left-hand side variable? What is the rule for that? – Leem.fin Dec 14 '11 at 15:04
  • It'll be the leftmost non-nil or non-false value (if none meet this criteria, 'car' will keep its original value) - as above. – Dave Dec 14 '11 at 15:08
  • 1
    Thank you Dave. I got what I prefer to know. – Leem.fin Dec 14 '11 at 15:09
  • Be careful, `a ||= b` is not strictly equivalent to `a = a || b`. http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html – Benjamin Crouzier Apr 19 '13 at 07:49
4
car ||= (method_1 || method_2) 

is equivalent to

car = (car || (method_1 || method_2)) 

In general,

x op= y 

means

x = x op y
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • @Leem.fin: You see my edit as well. `car ||= anything` means `car = car || anything` – Armen Tsirunyan Dec 14 '11 at 14:45
  • Oh! I see. I thought it will '||' with all the possible combinations with the right side part of '=' sign that's why I add more methods . – Leem.fin Dec 14 '11 at 14:46
  • @ Armen, what do you think about @Dave's explanation – Leem.fin Dec 14 '11 at 14:49
  • Dave shows the ||= operator in action: once it has been invoked on the first line, x contains a 'non-falsy' value and the second line does nothing. – seph Dec 14 '11 at 15:01
  • 1
    -1. This is wrong. `a ||= b` is much more like `a || a = b` than `a = a || b`, although it is in fact not equivalent to *either one* of those. – Jörg W Mittag Dec 14 '11 at 16:42
3

the ||= operator checks first, if your value car is already set. If car returns nil, it will assign the first value on the right side which doesn't return nil or false.

So, given your example from above, if you assign a value to car like

car = "BMW"

and you execute you code-snippet, the value of car will still be "BMW";

If method_1 returns (for instance) the String "Value from Method 1" and car is nil or false, then car this String will be assigned to car

car = nil
car ||= (method_1 || method_2)
car # => "Value from Method 1"

If method_1 also returns nil/false, it will check for the value in method_2, and so forth, until it gets some sort of true-value

The difference to your second code-snippet is, that in case of ||= the variable car will be evaluated first, and set if it returns nil or false.

If you use =only, no evaluation will happen and car will be set to the first value on the right that doesn't return nil or false.

-- UPDATE --

To answer your update question, the value on the right side will be evaluated from left to right, so the first one that doesn't return nil or false will be assigned.

car = nil
# method_1 => "nil"
# method_2 => "false"
# method_3 => "value method 3"
# method_4 => "I won't be called"

car ||= (method_1 || method_2 || method_3 || method_4)
# => "value method 3"
klaffenboeck
  • 6,297
  • 3
  • 23
  • 33
1
car ||= (method_1 || method_2 || method_3 || method_4)  

car will retain its value after this statement is run, if car initially is not nil.

If car was nil before this statement, the first non nil value to return from method_1, method_2, ... will be assigned to car.


car = method_1 || method_2 || method_3 || method_4

In this case, car will be re-assigned the first non nil value to return out of the methods even if car already has a non nil value before this statement ran

Guilherme Bernal
  • 8,183
  • 25
  • 43
Kalyan Maddu
  • 4,123
  • 2
  • 21
  • 26
0

car ||= (method_1 || method_2)

is equal to

car = car || (method_1 || method_2)

yerlikayaoglu
  • 344
  • 3
  • 11
  • -1. This is wrong. `a ||= b` is much more like `a || a = b` than `a = a || b`, although it is in fact not equivalent to *either one* of those. – Jörg W Mittag Dec 14 '11 at 16:41
0

in short it's equal to:

car = car || method_1 || method_2

in more details, it's a bit more complex:

car = (defined?(car) && car) || (method_1 || method_2)

in any case, what comes after the ||= will only be executed if car:

  • is not yet defined
  • is false
  • is nil
zed_0xff
  • 32,417
  • 7
  • 53
  • 72
0

answer to update:

method_2 gets assigned since it is the first non-false, non-nil value in the list.

seph
  • 6,066
  • 3
  • 21
  • 19