I am getting NameError: undefined local variable or method
with ruby 2.1.2
As observed in this question, expressions like:
bar if bar = true
raises an undefined local variable error (provided that bar
is not defined prior) because bar
is read by the parser before it is assigned. And I believe that there used to be no difference with that with this expression:
bar if bar = false
The difference between the two is whether the main body is evaluated or not, but that should not matter if encountering an undefined local variable immediately raises an error before evaluating the condition.
But when I run the second code on Ruby 2.1.2, it does not raise an error. Has it been like that from before? If so, then what was the parsing discussion all about? If not, has Ruby specification changed? Is there any reference to that? What did it do in 1.8.7, 1.9.3, etc. ?
My answer is based on Ruby 2.1.2.
Adding with @Jörg W Mittag answer.
Another commonly confusing case is when using a modifier
if
:Rather than printing “true” you receive a NameError, “undefined local variable or method `a’”. Since ruby parses the bare a left of the if first and has not yet seen an assignment to a it assumes you wish to call a method. Ruby then sees the assignment to a and will assume you are referencing a local method.
The confusion comes from the
out-of-order
execution of the expression. First the local variable is assigned-to then you attempt to call a nonexistent method.Based on above explanation -
simply returns
nil
, as the expression has been evaluated as false, the body of the code associated with theif
modifier wouldn't be executed.nil
is being returned by any block in Ruby, by default when there is no explicit default value.Yes it changed in ruby 2.1.2
In
1.8.7
,1.9.3
,2.0.0
and even2.1.1
I get 2 warnings and no errors:whereas in the
2.1.2
version you mention I get 2 warnings and 1NameError
error.This is on my Ubuntu 14
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 namebar
, 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: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:
Compare with:
All together now:
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.