Feature #1303
closedA name considered a local variable on RHS of an assignment that defines it
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
Updated by shyouhei (Shyouhei Urabe) almost 16 years ago
- 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
Updated by phasis68 (Heesob Park) almost 16 years ago
=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
Updated by shyouhei (Shyouhei Urabe) almost 16 years ago
=begin
Agreed, but that confusion may be sourced from your defining nonintuitive method / variable names.
=end
Updated by headius (Charles Nutter) almost 16 years ago
=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
Updated by phasis68 (Heesob Park) almost 16 years ago
=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
Updated by tmat (Tomas Matousek) almost 16 years ago
=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
Updated by mame (Yusuke Endoh) over 14 years ago
- 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