There is no difference with regards to whether bar
is defined or not. In both cases, bar
is undefined in the body. However, in the latter case, the body is never evaluated, therefore it doesn't matter. You never resolve the name bar
, therefore you never get an error during name resolution.
Local variables are defined when an assignment is parsed.
They are initialized when an assignment is executed.
It's perfectly fine for a variable to be unitialized. It will just evaluate to nil
in that case:
if false
bar = 42
end
bar
# => nil
However, if the variable is undefined, then Ruby doesn't know whether a bare word is a local variable or a receiverless argumentless message send:
foo
# NameError: undefined local variable or method `foo'
# ^^^^^^^^^
# Ruby doesn't know whether it's a variable or a message send
Compare with:
foo()
# NoMethodError: undefined method `foo'
# ^^^^^^^^^^^^^
self.foo
# NoMethodError: undefined method `foo'
# ^^^^^^^^^^^^^
All together now:
foo()
# NoMethodError: undefined method `foo'
self.foo
# NoMethodError: undefined method `foo'
foo
# NameError: undefined local variable or method `foo'
if false
foo = 42
end
foo
# => nil
foo = :fortytwo
foo
# => :fortytwo
The trouble in this particular case is that the order in which the expressions are parsed (and thus the order in which variables are defined) does not match with the order in which the expressions are executed.
The assignment is executed first, which would make you assume that bar
would be defined in the body. But it isn't, because the body was parsed first and thus an I don't know whether this is a method or a variable node was inserted into the syntax tree before the assignment was ever seen.
However, if that node is never interpreted, i.e. the condition is false, then nothing bad will happen.