gwtmp01 / mac.com wrote:
> 
> On Apr 1, 2006, at 2:13 PM, Mike Austin wrote:
>>
>> Since you bring this up, there are a few more cases where implicit 
>> locals declaration causes unexpected behavior (if new to ruby that is):
>>
>> x = 10
>> (1..10).each { |i| x = x + i }  # x == 65
>> x = 10
>> (1..10).each { |i| x = i }  # x == 10
>>
>> So if you're assigning x to itself in some way, it recognizes x in the 
>> enclosing scope, else it creates a new local.  That's kind of a 
>> confusing rule.    Also, what if I wanted the first example to create 
>> a local?  How do I refer to the toplevel `x` in the second?
> 
> The 'x' in each of those blocks references the local variable 'x' 
> defined outside the block.
> In neither case is a new local variable 'x' created within the block.  
> In both cases a new
> local variable 'i' is created within the blocks and is only visible 
> within the individual block.
> 
> Here are the rules I use to understand local variable scope and blocks:
> 
> 1) Local variables *created* outside a block are visible inside the block.
> 
> 2) Local variables *created* inside a block are *not* visible outside 
> the block.
> 
> 3) Block arguments behave like *local* variables *not* formal (method) 
> arguments.
> 
> 
> If you combine 1 and 2 you see that block scope is sort of a one-way 
> barrier. Code inside the block can see variables created outside the 
> block but not the other way around.
> 
> The third rule is the one that throws everyone because most programmers 
> tend to think of block arguments as formal arguments that shadow any 
> similarly named variables outside the block but this is incorrect (in 
> Ruby).  Block arguments behave like *local* variables so if a block 
> argument has the same name as a variable in the enclosing scope then a 
> new local variable is *not* created.  On the other hand if there is no 
> local variable in the enclosing scope with the same name then a new 
> local variable *is* created and is only visible within the block (rule 2).
> 
> I believe it is rule 3) that Matz is considering changing for Ruby 2.0

Changing the hiding characteristics of formal arguments sounds like a good 
idea, but there's still a big problem of not being able to declare locals.  For 
example, given the following:

def test()
   a = 2
   Proc.new { Proc.new { a = 10 }.call() }.call()
   puts a
end

test()  => 10

Lexical closure are a very nice thing, but if I think I'm creating a local when 
in fact I'm modifying some value in the enclosing scope, then that's bad.  I 
think shadowing a parameters is a lot less dangerous, and a warning can be 
printed when that happens.  So the above would look like this:

Proc.new { Proc.new { var a = 10 }.call() }.call()


Mike