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"
Related
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"
I want to set a variable if it's not already defined, so I write
if defined?(var).nil?
var = true
end
puts "[#{var}]"
This behaves as expected, it will print [true]. But if I want to simplify the snippet and write:
var = true if defined?(var).nil?
puts "[#{var}]"
It will print [].
What is the difference between these two snippets ?
A local variable is defined from the point that the first assignment to it is parsed. Therefore, in your second snippet, the variable is defined at the point where you are calling defined? (since Ruby is parsed like English, i.e. left-to-right, top-to-bottom), therefore the condition is always false, therefore the assignment never gets executed, therefore, the variable never gets initialized. Un-initialized local variables evaluate to nil and nil.to_s is the empty string.
Consider the following.
a #=> NameError (undefined local variable or method `a' for main:Object)
defined?(a)
#=> nil
a #=> NameError (undefined local variable or method `a' for main:Object)
As no local variable a exists defined? returns nil but does not create the variable.
b = 1
c = defined?(b)
#=> "local-variable"
puts "cat" if c
cat
d = nil
e = defined?(nil)
#=> "nil"
e.nil?
#=> false
c ("local-variable") is truthy (logically true) because it is neither nil or false (the latter being falsy).
a #=> NameError (undefined local variable or method `a' for main:Object)
a = true if false
#=> nil
a #=> nil
This last result is an odd characteristic of Ruby. As soon as the parser sees the beginning of the assignment (a =) it sets a equal to nil. I understand this is done for efficiency reasons.
Case 1
d = defined?(var1)
#=> nil
e = d.nil?
#=> true
var1 = true (since e #=> true)
var1
#=> true
Case 2
var2 =
# var2 is set equal to nil
d = defined?(var2)
#=> "nil"
e = d.nil?
#=> false
var2 = true if false
var2
#=> nil
puts "[#{nil}]"
[]
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.
Two similar sentences have different behaviour. Is it ok?
Compare:
a = 123 unless defined? a
a # => nil
but...
unless defined? b
b = 123
end
b # => 123
Yes, this is the correct behaviour. Local variables are created and initialized with nil before assignment. So this code
a = 123 unless defined? a
a # => nil
is a rough equivalent of
a = nil
a = 123 unless defined? a # `a` is not undefined anymore.
a # => nil
Another example (even though c is not defined before this line, this code does not throw a NameError).
c = 2 unless c # => 2
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.