Bug #13543
closedlocal variable declaration
Description
The following code snippet generates a strange error:
def foo
@foo ||= "foo"
end
foo = foo.size
#=> undefined method 'size' for nil:NilClass (NoMethodError)
I expect the code to create a local variable foo which is assigned the value 3. I expect this because in assignment, the right size of = is always resolved before being bound to the left side of =. In my mind, foo should refer to the foo() method right up to the point that a value is assigned to the local variable which shadows it. It is confusing and unexpected to have a period of limbo in which foo() is overshadowed by an unassigned local variable mid-declaration.
In other languages, declaration and initial assignments are atomic, so this code would throw errors:
In python:
In rust:
But in ruby, a variable can be instantly declared and assigned to itself:
This goes against the common motifs of programming in ruby and other languages and can lead to the confusing error mentioned above. Is there a reason local variables should be declared prior to resolving the assignment expression in ruby? I could find no documented reason for this design choice, leading me to believe it is a bug.
Updated by eiko (eiko kokuma) about 9 years ago
- Description updated (diff)
Updated by eiko (eiko kokuma) about 9 years ago
- ruby -v set to 2.4.0rc1
Updated by Hanmac (Hans Mackowiak) about 9 years ago
Updated by eiko (eiko kokuma) about 9 years ago
true, the parser detects the local variable early on, but it does not ignore the method until the point of assignment:
def foo
@foo ||= "foo"
end
p local_variables #=> [:foo]
p foo.size #=> 3
foo = foo.size #=> NoMethodError
so, despite the fact that local variables are determined before run-time, there's a mechanic in place to make sure they don't shadow methods until they are assigned. but why shadow the method mid-assignment when that's not common language design or seemingly useful as a design choice?
sorry if i'm in the wrong place for this. i had wanted to discuss this with ruby experts before raising the issue as a potential bug, but outside of stackoverflow, i don't know how best to communicate with people who know ruby well.
Updated by duerst (Martin Dürst) about 9 years ago
- Status changed from Open to Rejected
As far as I understand, the detection of variables (and as a consequence the shadowing of methods with the same name) occurs in lexical order. That means that because in
the variable name comes before the method call, the second foo is already shadowed. Something similar also happens in e.g.
Here, it's even more clear that the if is evaluated first (and the assignment maybe never), but still, the variable is lexically earlier, and so the method is shadowed. See also https://bugs.ruby-lang.org/issues/1141 and other bug reports linked from there.
Updated by duerst (Martin Dürst) about 9 years ago
- Related to Feature #1141: assignment of variable in "right" if statement fails added