615

How can I check whether a variable is defined in Ruby? Is there an isset-type method available?

15 Answers 15

823

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"
Sign up to request clarification or add additional context in comments.

5 Comments

If you want to set a variable if it doesn't exist and leave it alone if it does, see @danmayer's answer (involving the ||= operator) below.
Here's another oddity I can into.. If you define a variable in an if-block for which the condition is never met, defined? still returns true for a variable defined within that block!
Is there a method like defined? that returns boolean?
To return true/false, !!defined?(object_name)
@jrdioko it's not the same, i.e. setter returns false value like nil or false, defeating the purpose of caching value in instance variable, and doing all reassigning again, with god-knows-what will be executed..
96

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.

9 Comments

This is very idiomatic Ruby too and very typical, by the way.
Just don't use ||= with boolean values, lest you feel the pain of confusion.
along with what @AndrewMarshall said, avoid this idiom with anything that might return nil as well unless you really want to evaluate the expression every time it's called when it does return nil
If you are working with booleans, and want the default value to be true if the variable wasn't explicitly set to false, you can use this construction: var = (var or var.nil?)
@ArnaudMeuret Sort of, not really. -- while it may not seem identical, it's worth reading the answers on that question.
|
71

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.

4 Comments

That's not necessary as nil evaluates to false when used in a test
Why not defined?(var) == nil ?
@vol7ron - That is perfectly valid syntax. Using the call to .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.
Which statement are you refering to ?!? Don't use an answer as a comment to something else.
19

defined?(your_var) will work. Depending on what you're doing you can also do something like your_var.nil?

2 Comments

+1 for 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...
16

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

3 Comments

What does this answer add that hasn't been said by the other answers?
It very nicely answers the question in one more useful way, doesn't it?
The ruby style guide says "Favor unless over if for negative conditions" github.com/bbatsov/ruby-style-guide
13

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
  1. method2 always returns nil.
  2. The first time you call method1, the @x variable is not set - therefore method2 will be run. and
  3. 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.

1 Comment

You are totally right, thank you for highlighting that specific caveat
10

Use defined? YourVariable
Keep it simple silly .. ;)

Comments

8

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.

1 Comment

Presumably because the nil? is optional.
6

You can try:

unless defined?(var)
  #ruby code goes here
end
=> true

Because it returns a boolean.

3 Comments

SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
to use an unless statement seems overly complicated
defined? does NOT return a boolean, but the type of what comes afterwards. This type can be truthy or falsy, but you should pay attention. The => true is misleading at best unless your "#ruby code " that "goes here" returns true.
5

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

Comments

3

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!

1 Comment

This is something I just came across. I was expecting 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.
3

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')

Comments

1

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

2 Comments

this is exactly what I was looking for. I need the value if the var exists.Thanks!
Not sure when this changed, but in rails 7.1 console, all these "try"s result in nil
1

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"

Comments

0

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! :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.