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.
||=
with boolean values, lest you feel the pain of confusion.
nil
as well unless you really want to evaluate the expression every time it's called when it does return nil
var = (var or var.nil?)
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?(var) == nil
?
.nil?
is more idiomatic, as they say. It's more "object-oriented" to ask an object if it nil
than to use a comparison operator. Neither is difficult to read, so use whichever one helps you ship more product.
defined?(your_var)
will work. Depending on what you're doing you can also do something like your_var.nil?
your_var.nil?
because it returns true of false and is much nicer to read and write than defined? var
. Thanks for this.
your_var.nil?
will result in error : undefined local variable or method your_var
when not defined before...
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
This is the key answer: the defined?
method. The accepted answer above illustrates this perfectly.
But there is a shark, lurking beneath the waves...
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.
nil?
is optional.
You can try:
unless defined?(var)
#ruby code goes here
end
=> true
Because it returns a boolean.
SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
unless
statement seems overly complicated
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!
NameError Exception: undefined local variable or method
, and was confused when the only assignment/mention of the variable was in an if block that wasn't getting hit.
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"
Success story sharing
nil
is initialized.||=
operator) below.defined?
still returns true for a variable defined within that block!defined?
that returns boolean?!!defined?(object_name)