599

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

the Tin Man
  • 155,156
  • 41
  • 207
  • 295
readonly
  • 326,166
  • 107
  • 202
  • 204

15 Answers15

804

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"
akuhn
  • 26,757
  • 2
  • 73
  • 88
Ricardo Acras
  • 35,322
  • 16
  • 68
  • 110
  • 94
    It is worth noting that variable which is set to `nil` *is* initialized. – skalee Feb 16 '11 at 13:18
  • 7
    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. – jrdioko Jul 12 '11 at 21:29
  • 2
    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! – elsurudo Aug 21 '16 at 15:02
  • 1
    Is there a method like `defined?` that returns boolean? – stevec Jul 01 '19 at 14:45
  • To return true/false, `!!defined?(object_name)` – stevec Jul 01 '19 at 15:31
  • @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.. – Andre Figueiredo Nov 27 '19 at 16:58
93

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.

Arnaud Meuret
  • 981
  • 8
  • 26
danmayer
  • 4,228
  • 1
  • 21
  • 14
  • 9
    This is very idiomatic Ruby too and very typical, by the way. – jrdioko Jul 12 '11 at 21:28
  • Thanks for this input ! I'm a ruby/rails beginner and came accross this syntax yesterday evening, had a hard time figuring out what it meant. Looks very handy ! – Pierre-Adrien Nov 07 '11 at 10:35
  • 39
    Just don't use `||=` with boolean values, lest you feel the pain of confusion. – Andrew Marshall May 18 '12 at 06:27
  • 6
    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` – nzifnab Nov 19 '12 at 23:58
  • Personally don't like methods with get_ on the front (hey it's not Java :)), I'd just call it "var" and expose it to the outside world that way. I do this a lot to hide @variables and default them without having to jump through lots of hoops. get_ feels very procedural, you might want to do all sorts of things in that method one day. – Ghoti Dec 05 '13 at 15:32
  • No magic here. Mere syntactic sugar for `@var = @var || SomeClass.new`. Just unroll any Ruby `..=` operator if you're having difficulties wrapping your mind around it (and this is completely unrelated do `defined?` BTW). No layman rubyist should use `defined?` anyway. – Arnaud Meuret Aug 28 '14 at 14:42
  • 1
    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?)` – Tony Zito Sep 19 '14 at 19:20
  • `||=` will not work for boolean `false`. let's say `a = false` `a ||= true` then `a == true` you should use `defined? a` for boolean case – Yoshi Dec 03 '15 at 11:49
  • 1
    @ArnaudMeuret [Sort of, not really.](http://stackoverflow.com/a/2505285/1863564) -- while it may not seem identical, it's worth reading the answers on that question. – Nic Mar 08 '16 at 19:42
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.

True Soft
  • 8,506
  • 6
  • 51
  • 79
foomip
  • 1,375
  • 11
  • 4
  • 11
    That's not necessary as nil evaluates to false when used in a test – Jerome Apr 05 '12 at 14:23
  • Why not `defined?(var) == nil` ? – vol7ron Apr 23 '13 at 22:17
  • @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. – juanpaco Oct 26 '13 at 13:05
  • Which statement are you refering to ?!? Don't use an answer as a comment to something else. – Arnaud Meuret Aug 28 '14 at 14:46
19

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

digitalsanctum
  • 3,243
  • 4
  • 27
  • 43
  • +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. – kakubei Jul 14 '13 at 16:15
  • 29
    `your_var.nil?` will result in error : `undefined local variable or method your_var` when not defined before... – Gobol Sep 09 '13 at 15:45
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
Taymon
  • 23,632
  • 9
  • 61
  • 83
user761856
  • 171
  • 1
  • 2
11

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
  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.

BenKoshy
  • 29,795
  • 12
  • 94
  • 75
10

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

Saqib R.
  • 2,759
  • 2
  • 25
  • 20
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.

6

You can try:

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

Because it returns a boolean.

Haris Krajina
  • 14,076
  • 12
  • 61
  • 77
Bruno Barros
  • 61
  • 1
  • 2
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
donnoman
  • 161
  • 1
  • 1
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')
leberknecht
  • 1,302
  • 12
  • 25
2

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!

Robert Klemme
  • 2,132
  • 17
  • 22
  • 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. – Paul Pettengill Sep 23 '15 at 21:34
2

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
John Donner
  • 455
  • 5
  • 13
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! :)

Elliott
  • 295
  • 2
  • 13
0

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"
stevec
  • 27,285
  • 13
  • 133
  • 181