607

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

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
readonly
  • 343,444
  • 107
  • 203
  • 205

15 Answers15

814

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
  • 27,477
  • 2
  • 76
  • 91
Ricardo Acras
  • 35,784
  • 16
  • 71
  • 112
  • 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
  • 2
    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
95

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
  • 985
  • 8
  • 26
danmayer
  • 4,326
  • 1
  • 22
  • 15
  • 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,675
  • 6
  • 54
  • 83
foomip
  • 1,395
  • 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,261
  • 4
  • 29
  • 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
  • 24,950
  • 9
  • 62
  • 84
user761856
  • 171
  • 1
  • 2
12

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.

BenKoshy
  • 33,477
  • 14
  • 111
  • 80
10

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

Saqib R.
  • 2,919
  • 2
  • 26
  • 21
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.

Sardathrion - against SE abuse
  • 17,269
  • 27
  • 101
  • 156
6

You can try:

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

Because it returns a boolean.

Haris Krajina
  • 14,824
  • 12
  • 64
  • 81
Bruno Barros
  • 61
  • 1
  • 2
  • `SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND` – Andrew Grimm Aug 02 '12 at 23:11
  • to use an `unless` statement seems overly complicated – johannes Oct 29 '12 at 08:38
  • `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`. – Cadoiz Apr 03 '23 at 12:02
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,526
  • 15
  • 27
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,149
  • 18
  • 23
  • 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
  • 524
  • 6
  • 14
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
  • 325
  • 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
  • 41,291
  • 27
  • 223
  • 311