Issue #6070 has been updated by George Koehler.


=begin
This patch (for_loop_scope_fix_0224.diff) introduces a confusing change. With current Ruby, for loops and loops never have local variables. With this patch, for loops have local variables, but while loops never have them. Here is a brief example.

 [nil].each do |i|
   x = "x is string"
 end
 puts((x rescue "x not defined"))
 
 for j in [nil]
   y = "y is string"
 end
 puts((y rescue "y not defined"))
 
 while true
   z = "z is string"
   break
 end
 puts((z rescue "z not defined"))

With current Ruby, y and z are not local to their loops.

 $ ../tool/runruby.rb -v
 ruby 2.0.0dev (2012-03-01 trunk 34861) [x86_64-openbsd5.0]
 $ ../tool/runruby.rb ~/scratch.rb 
 x not defined
 y is string
 z is string

After applying for_loop_scope_fix_0224.diff, y is local to its for loop, but z is not local to its while loop.

 $ ../tool/runruby.rb ~/scratch.rb 
 x not defined
 y not defined
 z is string

With for_loop_scope_fix_0224.diff, it is difficult to understand why for loops can restrict scope of variables, but while loops never do so.

=end

----------------------------------------
Feature #6070: The scope of for loop variables
https://bugs.ruby-lang.org/issues/6070

Author: Shugo Maeda
Status: Open
Priority: Normal
Assignee: Yukihiro Matsumoto
Category: core
Target version: 2.0.0


Hi,

In Ruby, the scope of a for loop variable is not limited in the for expression,
which means that a for expression counts on side effects.

This sometimes causes unexpected behavior when closing a for loop variable using a closure.

  $ cat test.rb
  procs = []
  for lang in ["Ruby", "Scala", "Haskell"]
    procs << -> { p lang }
  end
  procs.each(&:call)
  $ ruby test.rb
  "Haskell"
  "Haskell"
  "Haskell"

Why not make a for loop variable local to the for expression like a block parameter?
In Ruby 1.8, a for expression is faster than a method call with a block, but it's not
true in Ruby 1.9, so there is no reason to give a for expression special treatment.

The compatibility might be a problem, but I believe that code depending on the current behavior is evil.
Ruby's for expression also allows a global variable and a method call as a for loop variable.  However,
I rarely see such code in real-world applications.

Furthermore, I've heard that the scope of a foreach loop variable is changed in C# 5.

  http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx?PageIndex=3

Why should Ruby be more conservative than C#?

I've attached a patch for POC.

There is at least one problem in this patch.  The problem is that it cannot handle
the following code in mkmf.rb.
# I suspected that this code was written by nobu, but it was written by Eric.

  for lib in libs = $libs.split
    ...
  end

It's because libs is considered local to the for expression in parsing phase, but the variable
can't be found in dyna vars in compiling phase.  I'm wondering how this code should behave and
how to implement it.



-- 
http://bugs.ruby-lang.org/