Clint
4/1/2006 9:50:00 PM
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