I don't understand ruby local scope

There a couple of things going on here. First, variables declared inside the if block have the same local scope as variables declared at the top level of the method, which is why bar is available outside the if. Second, you're getting that error because bob is being referenced straight out of the blue. The Ruby interpreter has never seen it and never seen it initialized before. It has, however, seen bar initialized before, inside the if statement. So when is gets to bar it knows it exists. Combine those two and that's your answer.


Your second example is actually a red herring: the reason why you are getting an exception is not because bob is uninitialized, it's because it is ambiguous. It's impossible to tell whether it's a variable or a method.

Your first example works, because uninitialized local variables (as well as global variables and instance variables) evaluate to nil. Therefore, puts bar is perfectly fine: in one case bar is initialized to 100 and this evaluates to 100, in the other case it is uninitialized and thus evaluates to nil. puts calls to_s on its argument, which is defined for nil (it simply returns the empty string), so everything is fine and dandy.

See also In Ruby, why after starting irb, foo.nil? says undefined error, and @foo.nil? gives “true”, and @@wah.nil? gives error again?


So don't take this as gospel (since it is more based on observation then understanding), but it seems like the ruby interpreter will flag any word (without a sigil in front of it) to the left of an equals sign as a local. Your example is strange, this is even more bizarre

def foo
  bar = bar
  puts bar // nil, which gets coerced into ""
end

I don't understand why or how it works, but there you have it.


foo(3) doesn't output nothing. It outputs a newline.

Using inspect would give you more of a hint:

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bar.inspect
end

foo(3)

prints out

nil

bar is a fully-fledged variable, which just happens to have a value of nil.