36
def foo
  #bar = nil
  if true
    bar = 1
  else
    bar = 2
  end
  bar #<-- shouldn't this refer to nil since the bar from the if statement is removed from the stack?
end

puts foo # prints "1"

I always thought you had to make a temporary variable and define it as nil or an initial value so that variables defined inside an if/else statement would persist outside the scope of the if/else statement and not disappear off the stack?? Why does it print 1 and not nil?

isherwood
  • 58,414
  • 16
  • 114
  • 157
bigpotato
  • 26,262
  • 56
  • 178
  • 334

1 Answers1

88

Variables are local to a function, class or module defintion, a proc, a block.

In ruby if is an expression and the branches don't have their own scope.

Also note that whenever the parser sees a variable assignment, it will create a variable in the scope, even if that code path isn't executed:

def test
  if false
    a = 1
  end
  puts a
end

test
# ok, it's nil.

It's bit similar to JavaScript, though it doesn't hoist the variable to the top of the scope:

def test
  puts a
  a = 1
end

test
# NameError: undefined local variable or method `a' for ...

So even if what you were saying were true, it still wouldn't be nil.

Community
  • 1
  • 1
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • 1
    Up-click for for the first two sentences, though I don't believe the rest added anything pertinent to the question. – Cary Swoveland Dec 21 '14 at 22:11
  • nice explanation, and the whole answer was absolutely relevant to the question, since the OP asked why the variable isn't `nil`. – cozyconemotel Aug 25 '20 at 10:18
  • It's probably worth to mention that the comparison with JavaScript is true for the `var` keyword but not for `const` and `let` which have become the recommended ways to define variables there. – kraf Jun 15 '22 at 08:55