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

What does the following code mean in Ruby?
||=
Does it have any meaning or reason for the syntax?

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:
http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html

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.

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.

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

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

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.

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 ||= b ⇔ a || 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 ||= b ⇔ a = 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 ||= b ⇔ a = 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 ||= b ⇔ defined?(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.

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

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

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

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

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.

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

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.

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.

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

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.

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

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.

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.

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

This ruby-lang syntax. The correct answer is to check the ruby-lang documentation. All other explanations obfuscate.
Google
"ruby-lang docs Abbreviated Assignment".
Ruby-lang docs
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment

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

Splat parameters behave differently for attribute writers compared to regular method

I have the following two methods, which I believe should have the same behaviour disregarding their names:
def a=(*params)
params
end
def b(*params)
params
end
But when in fact I use them:
a=(1) # => 1
b(1) # => [1]
(a=1) == b(1) # => false
while interestingly:
(a=1,2) == b(1,2) # => true
Why isn't their behaviour the same?
Edit: forgot to wrap the above in a class / call with self. which accidentally produces the same behaviour but for a different reason. It has been pointed out in the answers.
It has nothing to do with splat. It's the assignment operator. In ruby, the assignment operator returns the value assigned. The return value from the method is ignored.
So a=1 return 1, not [1].
But, as mentioned by #mudasobwa, you're not even calling the method here. But if you were, that's what would happen (ignoring the return value).
class Foo
def a=(*params)
params
end
end
f = Foo.new
f.a = 1 # => 1
f.a = 1,2 # => [1, 2]
To not ignore the return value, call that setter without using assignment operator.
f.send 'a=', 1 # => [1]
The thing is that
a = 1
sets the local variable and does not call your method at all. Try with
def a=(*param)
puts "I AM HERE"
end
var= methods require an explicit receiver. To call your method, call it with an explicit receiver:
self.a = 1
It still won’t return anything but 1, because assignment methods return the value (the same way as initialize called through MyClass.new returns an instance, no matter what.) But you might check that splat works with:
def a=(*param)
puts param.inspect
end
self.a = 1
# [1]
#⇒ 1

Global vs local variables?

I am wondering why my code works in one instance but doesn't in another. Does it have something to do with local and global variables?
This works:
def factorial num
result = 1
while (num > 1)
result = result * num
num -= 1
end
puts result
end
This doesn't work:
result = 1
def factorial num
while (num > 1)
result = result.to_i * num
num -= 1
end
puts result
end
Everything inside of a method definition cannot see local variables from other places. That sounds weird, but here's two ways to fix it:
result = 1
number = 10
def factorial(num,result_value)
while (num > 1)
result_value = result_value.to_i * num
num -= 1
end
puts result_value
end
factorial(number, result)
That passes result as an argument. That's a great way of handling the method because it doesn't allow you to change the value of result from within the method. That might not seem like a big deal but "pure methods" like this become very valuable as the size the code increases.
This is the "dirty" or un-pure way of doing the same thing:
#result = 1
def factorial(num)
while (num > 1)
#result = #result.to_i * num
num -= 1
end
puts #result
end
Putting an # in front of a variable name allows its scope to expand to methods defined outside of its scope. This becomes a problem as the complexity of your code increases.
Random personal opinion: even though Ruby doesn't require you to put the parentheses next to a method definition, you always should. It makes the code a lot more explicit and easier to read. Follow your heart though ;)
You could experiment by prepending all results with a $ sign, making it global. Prepending with a # results in an instance variable, also interesting. Sidenote: puts prints and returns nil, so your method returns nil.
result = 1 # line 1
def factorial num
while (num > 1)
result = result.to_i * num
num -= 1
end
puts result
end
In this code, factorial doesn't know about result variable from the line 1.
When Ruby find result = result.to_i * num in your method it will first assign nil to the result. Then Ruby will try to run result.to_i * num. Since result is already nil, result.to_i is equal 0.
Here is another example:
def foo
a = a
puts "#{a.class}"
end
foo #NilClass
In the Doesn't Work version the result variable you've assigned to 1 isn't visible inside the factorial method.
Now there is a possibly unexpected behaviour in Ruby that if you try to assign a variable and you refer to the same variable on the right hand side of the assignment, if that variable doesn't have a value yet then it is treated as nil rather than raising an error. So the first time round the loop when you perform
result = result.to_i * num
it's equivalent to result = nil.to_i * num and nil.to_i is equal to 0 so this then sets up result to be 0 for subsequent iterations of the loop and as you're just multiplying the value of result stays on 0.

Shorthand for "return x if x" in Ruby

One thing I love about Ruby is that you can express things in the shortest way possible.
I know that one can do, when assigning
x ||= a
# instead of
x = a unless x
# which is
x = x || a
Is there an analog form for return?
# instead of
return x if x
I'm trying to "say" x only once. This question asks about just returning (nothing), but I don't see how to do it when returning something other than void.
I'm just about certain that there exists no shorthand for your second example—nor could one be written without modifying the Ruby syntax—since it's not a common enough idiom. Sorry, bro, but it looks like you're going to have to be verbose on this one. (Though, really, as far as verbosity goes, this one isn't all that bad.)
(Note, too, that the first example isn't quite right: x ||= a is equivalent to x = x || a, which can also be expressed as x = a unless x.)
you can omit the return if it is the last statement in a block code.
example
irb(main):002:0> def b(c)
irb(main):003:1> c if c
irb(main):004:1> end
=> nil
irb(main):005:0> b(4)
=> 4
irb(main):006:0> b(nil)
=> nil
irb(main):007:0> b(true)
=> true
irb(main):008:0> b(false) # TADA!!!
=> nil

A float subclass that can be evaluated to false (fuzzy logic) in Ruby

I need a class that can represent probabilities. It can be represented like a float between 0 and 1, and anything below 0.5 should evaluate to false. (or it can be between 1 and -1, anything negative is false)
p = A.probability()
puts p # will output 0.3
if(p)
puts 'success'
else
puts 'failure'
end
# will outputs 'failure'
From this post it seems to suggest it is possible: every object has a boolean value... Most objects in Ruby will have a boolean value of true. Only two objects have a boolean value of false. Just that I need to set this boolean value somehow. So is this possible?
I wanted to do something similar, but unfortunately this is not possible in Ruby.
The only two objects that have a boolean value of false are false itself and nil. A few weeks ago I had a an internet chat (IRC) discussion with Brixen, one of the main developers of rubinius, and he explained it pretty well. My understanding is that when Ruby decides whether an object is true or not, it does NOT call any methods on (i.e. send any messages to) the object, it simply looks at the pointer it has to the object to see whether the pointer itself is equal to false or nil. Since it doesn't call any methods on the object, there is no way for you to change the behavior.
The best you can do is something like this:
p = A.probability()
puts p # => 0.3
if p.to_bool
puts 'success'
else
puts 'failure'
end
There is no "cast to boolean" operator because, as David notes, falsiness is hard wired for false and nil and anything that isn't "falsy" is true. However, there is a logical negation operator so you can do it if you don't mind an explicit cast to boolean:
class P
attr_accessor :p
def !#
p < 0.5
end
end
And then:
>> p = P.new
>> p.p = 0.75
=> puts 'Pancakes!' if(!!p)
Pancakes!
>> p.p = 0.25
>> puts 'Pancakes!' if(!!p)
# No pancakes for you
All the double bangs might be a bit ugly but, on the upside, it might make people notice that something a little non-standard is going on.
First of all, you do not need a Float subclass. Those interested in subclassing Numeric types can see Katzuda's answer.
The simple way to achieve what you want to achieve is to simply use a method:
class P
def initialize p; #p = p
raise "outta range" unless 0 <= #p and #p <= 1 end
def success?; SUCC <= #p end
def fail?; not success? end
end
p = P.new 0.3
p.success? # => false
p.fail? # => true
q = P.new 0.7
q.success? # => true
q.fail? # => false
Remember, for these kind of circumstances, Ruby has methods.

Why is my instance_variable nil? (2 lines of code)

I'm trying to create a hash which stores an auto-increment number for a non-existent key.
I'm aware there are other, less brittle, ways to do this; my question is : why does my instance variable fail so miserably?
h = Hash.new{|h,k| h[k] = (#max_value += 1)}
h.instance_variable_set(:#max_value, 0) # zero ! Not nil! Argh...
puts h[:a] # expecting 1; getting NoMethodError undefined method '+' for nil:NilClass
puts h[:b] # expecting 2
puts h[:a] # expecting 1
You're not doing what you think you're doing.
When you call Hash.new, you're referencing #max_value as it exists right now in the current scope. The current scope is the top level, it's not defined there, so you get nil.
You then set an instance variable on the instance that happens to be called #max_value as well, but it's not the same thing.
You probably want something like...well, actually, I can't imagine a situation where this mechanism is a good solution to anything, but it's what you asked for so lets run with it.
h = Hash.new{|h,k| h[k] = (h.instance_variable_set(:#max_value,
h.instance_variable_get(:#max_value) + 1))}
h.instance_variable_set :#max_value, 0
puts h[1] #=> 1
puts h[10] #=> 2
Note that I'm explicitly getting/setting the instance variable associated with `h in all cases. More verbose, but what you need.

Resources