From: Mike Austin Date: 2006-04-02T06:53:44+09:00 Subject: Re: Eval needs explicit self for accessor methods? 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