-
-
Save moxley/3753161 to your computer and use it in GitHub Desktop.
class MyClass | |
def value | |
"VALUE!" | |
end | |
def do_something | |
puts value # Outputs "VALUE!" | |
if false | |
value = nil # Should not execute | |
end | |
puts value # Outputs nothing | |
end | |
end | |
MyClass.new.do_something |
The first value is parsed as a method call (a vcall in MRI parser terms), so it calls your value method. Even though the value = nil is inside an "if false" block, from then on the parser sees it as a local variable. Since it is never actually initialized, it gets the default value of nil, and so puts prints a blank line for the third reference to "value".
Local variable declarations are made regardless of whether the code is reached in the method. But existence of the declaration does depend on position in the flow of execution. And given that local variables shadow methods, unless you use an explicit receiver.
I think the rationale is that you could be just use any local variable that may have been declared in the flow of execution but you don't have to check its existence, because you can't really, unless you use meta programming.
First call there is no definition of 'value' in the local scope, so it looks up to the instance, and finds the value method.
The interpreter then sees a definition of the 'value = nil' initializing 'value' as a local variable. The last puts outputs the value of 'value'. It's clearer what's happening if you change the 'value = nil' line to 'value = "value"' -- you still get
VALUE!
nil
Local variable assignments in "keyword" blocks always result in that local variable being defined. If you did "for i in []" or "case...when false" it'd work, too. However, "[].each do" would not, nor would any other construct based around an explicit do/end block.
As I understand it, this is sort of an artifact of how local assignments inside "keyword" blocks are made inside the enclosing scope.
Shorter answer: if/case/while/etc. do not create a new scope for local variables, and local variables are defined in these constructs when they are parsed, not when they are executed.
in your last puts, do this
puts value.inspect