I am using Ruby on Rails 3 and I have this situation:
In a controller I have
# first statement
if a == true
flag = true
end
# second statement
if flag == true
// code1
else
// code2
end
If a is false, what happens in the if statement without having initialized the flag variable? That is, is the flag variable "always"/"in any case" set to NOT TRUE?
Is it a safe approach?
You can try this sort of thing out in irb:
>> if false
>> foo = "bar"
>> end
=> nil
>> foo
=> nil
So you can see that even though the if condition is false, the foo variable is introduced (it is nil, which will be treated the same as false in your if, so you are safe). I suspect that this is because if statements don't introduce a new scope. See:
>> if true
>> bar = "baz"
>> end
=> "baz"
>> bar
=> "baz"
One final thought: If A is really just a boolean, you could set flag = A and avoid the if altogether.
An unassigned variable is equal to nil but constants work a little differently. With a variable anything other than nil or false will evaluate to true. With a constant you need to use definded?(CONSTANT) so your code would look like this:
# first statement
flag = A if defined?(A)
# second statement
if flag
puts "Code 1"
else
puts "Code 2"
end
# Or if you don't need the flag variable
if defined?(A) && A
puts "Code 1"
else
puts "Code 2"
end
Output:
Code 2
Code 2
Related
In ruby, let's suppose we have this code:
foo = nil
if foo
puts "foo is true"
else
puts "foo is false"
end
what will this above program print exactly?
Usually, Ruby developers do not care that much if a variable or condition is exactly true or false. Instead Ruby has the concept of truthy and falsey values.
false and nil are falsey, everything else is truthy.
In your example
if foo
puts "foo is true"
else
puts "foo is false"
end
the output would be "foo is false" because nil is falsey and therefore the else block is evaluated.
When running the example in the console then nil would be returned at the end, because nil is returned by the puts method (see docs) and the Ruby console always returns the return value of the last method call.
The answer is that code above will print "foo is false" and also output nil. If someone knows why please comment on this answer or post a new answer to the above question.
So,
if foo
puts "foo is true"
else
puts "foo is false"
end
will print:
foo is false
=> nil
if you are using ruby console
Update: The user "spickermann" explained it perfectly here I think, link
I was hoping someone could help me with identifying the most idiomatic way to test if a variable is nil or false implicitly for the sake of readability.
Here is my explicit example:
if somevar.nil? # explicitly checking for nil.
puts "Its nil."
end
Is it better to write:
if !somevar # implicit
puts "Var is nil or false."
end
I really like this way:
if not somevar # implicit
puts "Var is nil or false"
end
From what I am reading, testing for nil explicitly should be avoided to some extent as its generally not needed. Most examples suggest to take action only if a variable exists. However, I want to perform an action when a variable does not exist.
Main inspiration for ditching nil came from: ruby_idioms
def truthiness(value)
if value
"truthy"
else
"falsy"
end
end
puts "nil:", truthiness(nil) # falsy
puts "false:", truthiness(false) # falsy
puts "true:", truthiness(true) # truthy
puts "[]:", truthiness([]) # truthy
puts "{}:", truthiness({}) # truthy
puts "0:", truthiness(0) # truthy
I know you know Python, so I can say that:
In Python, None, False, and empty containers such as [], {}, and even 0 are all falsy.
In Ruby, nil and false are falsy, whereas most other things are truthy, even [], {}, and 0.
I think the most idiomatic way in ruby for testing whether something is false or nil is using unless:
unless somevar
puts "Var is nil or false."
end
From the ruby style guide
Favor unless over if for negative conditions (or control flow
||).
# bad
do_something if !some_condition
# bad
do_something if not some_condition
# good
do_something unless some_condition
# another good option
some_condition || do_something
You can use defined? keyword :
defined? expression tests whether or not expression refers to anything recognizable (literal object, local variable that has been initialized, method name visible from the current scope, etc.). The return value is nil if the expression cannot be resolved. Otherwise, the return value provides information about the expression.
unless defined?(var)
#your code
end
Quick PRY to test, what the defined? returns when a variable is defined and when not :-
arup#linux-wzza:~/Ruby> pry
[1] pry(main)> defined?(x)
=> nil
[2] pry(main)> x = nil
=> nil
[3] pry(main)> defined? x
=> "local-variable"
[4] pry(main)>
I have a curiosity with variable definition. I know about variable definition, it's just to understand how it works. The idea is to set myvar to 0 if it is not defined. I don't want to use false because false could be returned by false or nil.
def foo
myvar=1000
myvar = ((defined? myvar)==nil) ? 0 : myvar
puts myvar
end
foo # => 1000
but
def foo
# myvar=1000
myvar = ((defined? myvar)==nil) ? 0 : myvar
puts myvar
end
foo # => nil
but
def foo
mybool = ((defined? myvar)==nil)
myvar = mybool ? 0 : myvar
puts myvar
end
foo # => 0 it rocks !
It's like if the boolean test was affected to myvar before the final test was evaluated.
((defined? myvar)==nil) gives 2 possibilities defined? myvar could be nil or the right side of test nil could be nil (it's nil).
To get rid of the nil part of this test, I tried this code :
def foo
mylocalvariable = 2 # it gives 'local-variable' and not nil
puts ((defined? myvar) == (defined? mylocalvariable ))
myvar = ((defined? myvar)!=(defined? mylocalvariable )) ? 0 : myvar
puts myvar
end
foo # => nil
It seems the first part of the test was affected to myvar, but assignment operators come after () or after comparison operator. Do you have an idea? I don't want an other code but just why it works like that.
Thank you.
You might not want other code, but you need some because you're going the long way around to accomplish something that is simple. If you want to set an undefined variable to 0 use:
myvar ||= 0
How does it work? ||= is a conditional assignment operator, that basically looks at the variable being assigned to on the left, and, if it's nil or false, assigns the value on the right to it. It's a trick found in many languages.
Ternary (?:) statements are useful for small if/then/else statements, but aren't really the right choice for what you want to do. Instead, if you want to use something besides ||=, use:
myvar = 0 unless myvar
Again, all of these will reassign myvar if it happens to be a false value, not just if it's nil. That's a potential problem, but, as developers, we're supposed to be in control and should have a good idea what type of value a variable is holding at any moment so it shouldn't be that big of a problem.
Hi this kind of operator is ternary operator.
Example:
#x = 1
#y = 2
#x>2 ? puts "YES" : puts "NO"
You can also check if it for an ActiveRecord
Example:
#x = User.find(:all, :conditions => ["id = ?", 1])
#x.nil? ? puts "Null" : puts "Not Null"
I know why. When you code myvar= and you test defined?myvar, ruby consider myvar defined. If you remove myvar= , myvar is considered undefined in the test.
The left part is read before the right part.
What's going on here? What is the subtle difference between the two forms of "unless"?
> irb(main):001:0> foo = true unless defined?(foo)
=> nil
irb(main):002:0> unless defined?(fooo) ; fooo = false ; end
=> false
thx
Apparently, ruby creates local variable at parse time setting them to nilso it is defined and this is done whether the code is executed or not.
When the code is evaluated at your first line, it doesn't execute the assignment part since foo is set to nil. In the second line, because fooo has not been parsed yet, defined?returns nil letting the code inside the block execute and assign fooo.
As an example you can try this:
if false
foo = 43
end
defined? foo
=> "local-variable"
This is taken from a forum post at ruby-forum.
Let's start with something simpler:
# z is not yet defined
irb(main):001:0> defined?(z)
=> nil
# Even though the assignment won't execute,
# the mere presence of the assignment statement
# causes z to come to life.
irb(main):002:0> z = 123 if false
=> nil
irb(main):003:0> defined?(z)
=> "local-variable"
irb(main):004:0> z
=> nil
Now we can figure out your first example.
foo = true unless defined?(foo)
Is foo defined? Before we press ENTER in irb, no. However, the presence of the assignment statement causes foo to come to life. That means the assignment statement won't be executed, leaving foo in existence but having nil as its value. And what is the last expression evaluated in the irb line? It is unless defined?(foo), which evaluates to nil.
For more info on how assignments (even those that do not get executed) cause variables to exist, see this discussion of Variable/Method Ambiguity.
In your second example, there is nothing mysterious at all: fooo is not defined, so the code in the block executes, setting fooo to false. That assignment is the last expression evaluated, so false is the return value of our block.
irb(main)> foo = true unless defined?(Integer)
=> nil
irb(main)> foo = true unless defined?(thisIsUndefined)
=> true
Your first block is returning nil because the way it's written leaves 2 options:
foo is not defined --> assign true
foo is defined --> do nothing
Here, foo must be defined when the line is evaluated. Thus, nothing happens and nil is returned.
irb(main)> unless defined?(Integer) ; fooo = false ; end
=> nil
irb(main)> unless defined?(thisIsUndefined) ; fooo = false ; end
=> false
Your second block operates the same way your first one does. If fooo is not defined, the block is entered and fooo is set to false. The result of the last line of the block is the return value of the block, thus the false you are seeing. If fooo does exist, then the block is skipped over and nothing happens, therefore there is nothing to return, therefore the nil.
Based on your code, I would say that foo was defined when this code was run and fooo was not (test code shown was generated in Ruby 1.8.6). If you did not define either of these before running this code, then you may have something called foo that is defined by default (do defined?(foo) by itself to check). Try using a different name and see if you get the same results.
Edit:
irb(main)> defined?(bar)
=> nil
irb(main)> bar = true unless defined?(bar)
=> nil
irb(main)> defined?(bar)
=> "local-variable"
Apparently, defined?() is returning true since it has already seen bar (at the beginning of the line), even though you are still in the process of defining it.
in the first instance you call foo into existence in the assignment statement. Maybe this will clarify:
bar = if true
puts bar.class
else
puts "not reached"
end
NilClass
=> nil
baz = if true
puts baz.class
42
else
puts "not reached"
end
NilClass
=> 42
August, all look fine in 1.8.7:
$ irb
irb(main):001:0> unless defined?(fooo); fooo = true; end
=> true
irb(main):002:0> fooo
=> true
irb(main):003:0> `ruby --version`
=> "ruby 1.8.7 (2008-06-20 patchlevel 22) [i486-linux]\n"
Well.. One form is a block and one form isn't. The second part, the block, returns the last statement evaluated. The first one.. Hrm.. I don't know exactly what it's doing.
In Ruby 1.8.7:
foo = true unless defined?(foo)
p foo # => nil
unless defined?(fooo); fooo = true; end
p foo # => nil
I don't have an explanation for the behaviour you are seeing.
How can I check whether a variable is defined in Ruby? Is there an isset-type method available?
Use the defined? keyword (documentation). It will return a String with the kind of the item, or nil if it doesn’t exist.
>> a = 1
=> 1
>> defined? a
=> "local-variable"
>> defined? b
=> nil
>> defined? nil
=> "nil"
>> defined? String
=> "constant"
>> defined? 1
=> "expression"
As skalee commented: "It is worth noting that variable which is set to nil is initialized."
>> n = nil
>> defined? n
=> "local-variable"
This is useful if you want to do nothing if it does exist but create it if it doesn't exist.
def get_var
#var ||= SomeClass.new()
end
This only creates the new instance once. After that it just keeps returning the var.
The correct syntax for the above statement is:
if (defined?(var)).nil? # will now return true or false
print "var is not defined\n".color(:red)
else
print "var is defined\n".color(:green)
end
substituting (var) with your variable. This syntax will return a true/false value for evaluation in the if statement.
defined?(your_var) will work. Depending on what you're doing you can also do something like your_var.nil?
Try "unless" instead of "if"
a = "apple"
# Note that b is not declared
c = nil
unless defined? a
puts "a is not defined"
end
unless defined? b
puts "b is not defined"
end
unless defined? c
puts "c is not defined"
end
WARNING Re: A Common Ruby Pattern
the defined? method is the answer. See the accepted answer above.
But watch out... consider this common ruby pattern:
def method1
#x ||= method2
end
def method2
nil
end
method2 always returns nil.
The first time you call method1, the #x variable is not set - therefore method2 will be run. and
method2 will set #x to nil.
But what happens the second time you call method1?
Remember #x has already been set to nil. But method2 will still be run again!! If method2 is a costly undertaking this might not be something that you want.
Let the defined? method come to the rescue:
def method1
return #x if defined? #x
#x = method2
end
As with most things, the devil is in the implementation details.
Use defined? YourVariable
Keep it simple silly .. ;)
Here is some code, nothing rocket science but it works well enough
require 'rubygems'
require 'rainbow'
if defined?(var).nil? # .nil? is optional but might make for clearer intent.
print "var is not defined\n".color(:red)
else
print "car is defined\n".color(:green)
end
Clearly, the colouring code is not necessary, just a nice visualation in this toy example.
You can try:
unless defined?(var)
#ruby code goes here
end
=> true
Because it returns a boolean.
As many other examples show you don't actually need a boolean from a method to make logical choices in ruby. It would be a poor form to coerce everything to a boolean unless you actually need a boolean.
But if you absolutely need a boolean. Use !! (bang bang) or "falsy falsy reveals the truth".
› irb
>> a = nil
=> nil
>> defined?(a)
=> "local-variable"
>> defined?(b)
=> nil
>> !!defined?(a)
=> true
>> !!defined?(b)
=> false
Why it doesn't usually pay to coerce:
>> (!!defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red)) == (defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red))
=> true
Here's an example where it matters because it relies on the implicit coercion of the boolean value to its string representation.
>> puts "var is defined? #{!!defined?(a)} vs #{defined?(a)}"
var is defined? true vs local-variable
=> nil
It should be mentioned that using defined to check if a specific field is set in a hash might behave unexpected:
var = {}
if defined? var['unknown']
puts 'this is unexpected'
end
# will output "this is unexpected"
The syntax is correct here, but defined? var['unknown'] will be evaluated to the string "method", so the if block will be executed
edit: The correct notation for checking if a key exists in a hash would be:
if var.key?('unknown')
Please note the distinction between "defined" and "assigned".
$ ruby -e 'def f; if 1>2; x=99; end;p x, defined? x; end;f'
nil
"local-variable"
x is defined even though it is never assigned!
defined? is great, but if you are in a Rails environment you can also use try, especially in cases where you want to check a dynamic variable name:
foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo) # => 1
try(:bar) # => nil
try(my_foo) # => 1
try(my_bar) # => nil
Also, you can check if it's defined while in a string via interpolation, if you code:
puts "Is array1 defined and what type is it? #{defined?(#array1)}"
The system will tell you the type if it is defined.
If it is not defined it will just return a warning saying the variable is not initialized.
Hope this helps! :)
Leaving an incredibly simple example in case it helps.
When variable doesn't exist:
if defined? a then "hi" end
# => nil
When variable does exist:
a = 2
if defined? a then "hi" end
# => "hi"