Project

General

Profile

Actions

Feature #1303

closed

A name considered a local variable on RHS of an assignment that defines it

Added by tmat (Tomas Matousek) about 12 years ago. Updated almost 10 years ago.

Status:
Rejected
Priority:
Normal
Target version:
[ruby-core:22939]

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

Actions #1

Updated by shyouhei (Shyouhei Urabe) about 12 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

Actions #2

Updated by phasis68 (Heesob Park) about 12 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

Actions #3

Updated by shyouhei (Shyouhei Urabe) about 12 years ago

=begin
Agreed, but that confusion may be sourced from your defining nonintuitive method / variable names.
=end

Actions #4

Updated by headius (Charles Nutter) about 12 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

Actions #5

Updated by phasis68 (Heesob Park) about 12 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

Actions #6

Updated by tmat (Tomas Matousek) about 12 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

Actions #7

Updated by mame (Yusuke Endoh) about 11 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

Actions

Also available in: Atom PDF