Ruby ||= operator acting funny - ruby

From what I understand, a ||= 7 means the following:
if a has a value, continue using that value, but if it does NOT have one, then set it to 7.
Here is what happens though.
If i have a and b as:
a = true
b = false
then
a ||= b => true
(in my interpretation: since 'a' DOES have a value, it remains that, and does not get equated to 'false' - so far so good.)
However, if i have them switched up like:
a = false
b = true
then a ||= b => true
so in this case my logic does not work, since it should return false, as "since 'a' has a value, it should not be assigned the value of 'b'", which apparently happens here.
Am I missing something?

a ||= b
is equivalent to
a || a = b
this means b value is assigned to a if a is falsy, i.e. false or nil.

Related

Ruby Double Pipes Assignment

Just tripped over an instruction that is unclear:
a = 5 || 3 # ==> 5
verdict = true || false # ==> true
Since || is the same as or, how and/or why would this statement be used? It doesn't really demonstrate any decision making other than choosing the first option always.
I know the ||= assignment, but this is different. Looking for clarification on the usage above of || alone.
a = b || c
What this statement does is, it tells Ruby to 'assign the value of b to a, unless b is falsy, if b is falsy, assign the value of c to a. In case b isn't falsy, the c statement won't get executed.
A good example where you could use this is if you're getting a variable from somewhere and you're not sure if it's going to be nil or not, so you create a variable like c as a second option.
If you have a method that takes in a hash as a parameter for example, and you want to return the value of the element from the hash that has the key 'b' for example, but the hash parameter won't always have a 'b' key, so you write something like this
def value_of_b(hash)
b_val = hash['b'] || 'unknown'
puts "The value of b is :#{b_val}"
end
h = {'a' => 1, 'b' => 2}
value_of_b(h)
#=>The value of b is :2
m = {'a' => 1}
value_of_b(m)
#=>The value of b is :unknown
Another example that comes to my mind is accessing an array element that doesn't exist
[1,2,3][3] || "default"
#=> "default"
Or having a default value for Rails params hash:
#name = params[:name] || "no name provided"

Ruby: difference between &= and &&=

I have the impression I can use
bool &= true
# and
bool &&= true
# indifferently
Is there any difference between two? Is one solution unrecommended?
Actually
bool = true & false # false
So what's the difference between & and && in general? (I guess the same applies for ||)
Try the following:
x = 5
x |= 2
=> 7
|= and &= are equivalent to the bitwise x = x | 2 and x = x & 2
vs
x = 5
x ||= 2
=> 5
In the second statement, x ||= 2, it means x = 2 if x is nil, otherwise it's x.
( x = (x || 2) ; the expression x || 2 returns x if x is anything but nil otherwise it returns 2.
x ||= 'foo' is actually very common in Ruby (set x to foo is x is not already set)
x = (x & 3) (which is equivalent to x &= 3), returns 3 (the second operand) unless x is 0, it returns 0)
)
The same logic applies for & but it was easier to find an example on the top of my mind for |
=)
The main difference between the keywords is that the first | is a method, and can be redefined for a class, and the second || is not, and can be never defined as a method, and just used for language syntax, as you can see in example below:
Array.new.respond_to?( :| )
# => true
Array.new.respond_to?( :|| )
SyntaxError: (irb):35: syntax error, unexpected tOP_ASGN, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
So, when you have applied the #| method it is able to return a value that differs from true, or false. Although for ruby's TrueClass, and FalseClass those values are true or false, but other descendants could redefine the return value, however, for Array and Set classes it implements functions similar to boolean bitwise operation. So can be sure that the true or false class's methods return also true or false. Otherwise, the keyword || is real language boolean operator, however it operates with values true, and not-true, you can see it on example:
'value1' || 'value2'
# => "value1"
true || false
# => true
'value1' || false
# => "value1"
false || 'value2'
# => "value2"
The return valus is always subordinated to logical expression, but the values of it are, as I denoted above, true, and not-true. Therefore you see in example return values not only of true/false pair, but of the real variable values too, and you can use it as if conditional operators as follows:
'value1' || 'value2'
and
if 'value1'
'value1'
else
'value2'
end
will return the same value.
According the or-equal assignment we see the following:
A |= false
# NameError: uninitialized constant A
a |= false
# false
A ||= false
# => false
In first case we are able to split |= operation into the two: call to #| method, and to assign the result to the variable. In the second case the ruby interpreter sees the whole operator ||=, verifies weither it is nil or undefined, and if yes assign to the variable or to the const the expression result.
The pair &, && has the same explanation.
When you are only using the & operator on boolean values, then there is no difference to &&, but if you want to use it with functions that return a boolean value then there is a difference. Have a look at this code:
def side_effect(message="hello")
puts message
true
end
#writes "hello" 2 times to the console and then returns false
false & side_effect & side_effect
# just returns false without writing "hello" to the console.
false && side_effect && side_effect

Use case for `&&=`

I have seen and used by myself lots of ||= in Ruby code, but I have almost never seen or used &&= in practical application. Is there a use case for &&=?
Not to be glib, but the obvious use case is any time you would say x && foo and desire the result stored back into x. Here's one:
list = [[:foo,1],[:bar,2]]
result = list.find{ |e| e.first == term }
result &&= result.last # nil or the value part of the found tuple
any sort of iteration where you want to ensure that the evaluation of a boolean condition on all elements returns true for all the elements.
e.g.
result = true
array.each do |elem|
# ...
result &&= condition(elem) # boolean condition based on element value
end
# result is true only if all elements return true for the given condition
Validation of the document such as,
a = {'a' => ['string',123]}
where the element in a['a'] should be a String. To validate them, I think you can use,
def validate(doc, type)
valid = true
doc.each{|x|
valid &&= x.is_a? type
}
valid
end
1.9.3p392 :010 > validate(a['a'],String) => false

ruby condition sequence

I was under the impression that conditions joined with && were executed in sequence, such that the following would return true:
a = "adasd"
> b = a && b.present?
=> false
Thoughts?
Thanks!
--Peter
note:
b = a
=> "adasd"
b.present?
=> true
When you say this:
b = a && b.present?
You're declaring b as a local variable but it will be nil until the right side of the assignment is evaluated. In particular, b will be nil when you call present? on it and the conjunction will be false making b false.
When you do this:
a = 'pancakes'
b = a
b.present?
b will have the value 'pancakes' when you call present? on it so you get a true return from b.present?.
As per the rails doc
present is checking for a variable to be non blank
As per assignment timing, ruby declares the variable in the scope as soon as it sees it, so b will be in the scope but with no value, so present will return false.
You should maybe compared this with defined?
a = "abc"
=> "abc"
defined? a
=> "local-variable"
defined? b
=> nil
b = defined? b
=> "local-variable"

Set Ruby variable if it is not already defined

In Ruby, how do you set a variable to a certain value if it is not already defined, and leave the current value if it is already defined?
While x ||= value is a way to say "if x contains a falsey value, including nil (which is implicit in this construct if x is not defined because it appears on the left hand side of the assignment), assign value to x", it does just that.
It is roughly equivalent to the following. (However, x ||= value will not throw a NameError like this code may and it will always assign a value to x as this code does not -- the point is to see x ||= value works the same for any falsey value in x, including the "default" nil value):
if !x
x = value
end
To see if the variable has truly not been assigned a value, use the defined? method:
>> defined? z
=> nil
>> z = nil
=> nil
>> defined? z
=> "local-variable"
>> defined? #z
=> nil
>> #z = nil
=> nil
>> defined? #z
=> "instance-variable"
However, in almost every case, using defined? is code smell. Be careful with power. Do the sensible thing: give variables values before trying to use them :)
Happy coding.
#variable ||= "set value if not set"
So false variables will get overridden
> #test = true
=> true
> #test ||= "test"
=> true
> #test
=> nil
> #test ||= "test"
=> "test"
> #test = false
=> false
> #test ||= "test"
=> "test"
As you didn't specify what kind of variable:
v = v
v ||= 1
Don't recommend doing this with local variables though.
Edit: In fact v=v is not needed
If the variable is not defined (declared?) it doesn't exist, and if it is declared then you know how you initialized it, right?
Usually, if I just need a variable whose use I don't yet know---that I know will never use as a Boolean---I initialize it by setting its value to nil. Then you can test if it has been changed later quite easily
x = nil
some code
if x do
[code that will only run if x has changed]
end
that's all.

Resources