Feature #1303
closed
A name considered a local variable on RHS of an assignment that defines it
Added by tmat (Tomas Matousek) over 15 years ago.
Updated over 13 years ago.
Description
=begin
The following script defines a method "f" and then a variable "f" by an assignment [1]. There is a reference to "f" on RHS of the assignment. The parser treats this reference as a reference to the local variable "f", not to the method "f", since it has already seen an assignemnt to "f". However, one might expect that within the RHS of an assignment the local variable defined by the assignment should not be visible yet (and indeed its value is nil). The following code should therefore print 123 and and not nil.
def f
123
end
f = f.inspect # [1]
puts f
=end
- Assignee set to matz (Yukihiro Matsumoto)
=begin
I don't think it being a bug, but a language design. You can always resolve a method
by prefixing "self." to the method name, but you can never add a qualifier to a local
variable, so in cases of naming conflict between local variables vs. methods, it is
safer for ruby to take local variables, generally speaking. Multiple assignment can
go quite complex and LHS variables are not always nil when appearing on RHS.
irb(main):001:0> f, g, h = (f = 1), (f += 1), f.inspect
=> [1, 2, "2"]
=end
=begin
It is very confusing.
case 1
def f;123;end
g = f.inspect
f = g
puts f #=> 123
case 2
def f;123;end
f = g = f.inspect
puts f #=> nil
=end
=begin
Agreed, but that confusion may be sourced from your defining nonintuitive method / variable names.
=end
=begin
I agree with Shyouhei. There are many such cases where a variable may not yet have been assigned, but for consistency all future references should treat it as a variable.
Would you expect f to refer to the method or the variable after the if statement here:
def f; 123; end
if false; f = nil; end
f
Having a clear lifecycle for local variables that does not depend on what actually runs or doesn't run (or when it runs) is very important for both readability and performance. From the moment you see a direct assignment to f, it's a local variable from then on.
=end
=begin
Agreed
Considering
def f; 123; end
defined? f #=> "method"
defined? f() #=> "method"
f=nil
defined? f #=> "local-variable"
defined? f() #=> "method"
Calling a method with () is safe always.
=end
=begin
You're basically saying that it's a matter of syntactic structure, not control flow structure and I agree. There is still a choice to be made while parsing the assignment expression: the parser might "visit" RHS first and then define variables in LHS or the other way around. Both options are valid, prioritizing RHS might eliminate some confusion.
=end
- Status changed from Open to Rejected
=begin
Hi,
2009/3/19 Tomas Matousek redmine@ruby-lang.org:
the parser might "visit" RHS first and then define variables in LHS or the other way around. Both options are valid, prioritizing RHS might eliminate some confusion.
Your proposal will break recursive proc. Consider:
fact = proc do |n|
if n <= 0
1
else
n * fact[n - 1]
#=> undefined local variable or method `fact' for main:Object (NameError)
end
end
This is a significant incompatibility issue.
So I reject this ticket.
--
Yusuke ENDOH mame@tsg.ne.jp
=end
Also available in: Atom
PDF
Like0
Like0Like0Like0Like0Like0Like0Like0