On Wed, 14 Mar 2001, Johann Hibschman wrote:

> > The "i" is protected because it's defined in the |i| parameter list.
> > This is a nice way of just using a name for the loop without trashing
> > anything else. All other variables are just there and used, like BASIC.
> 
> Okay.  This here is the biggest source of errors for me in irb.  In
> real programs, I can avoid it, but in interactive use, I have trouble.
> Namely, I keep expected the variable in blocks to introduce a new
> local variable, like a function call.
> 
> i.e. I type
> x = [1, 2, 3, 4, 5]
> y = x.collect{|x| x**2}
> 
> And suddenly, I've overwritten x.  Maybe this is my lispy heritage
> showing, but I just don't expect this behavior.  The block looks like
> a function call, so I expect it to introduce a new local.

The syntax change I proposed would fix that problem. Here's how it would
look, the new way...

With {}'s...

  x = [1, 2, 3, 4, 5]
  y = x.collect{|x| x ** 2}

{}'s have their own scope, so x wouldn't be overwritten... hence behaving
as you expected. No change to the code and now it works. :)

With do..end's...

  x = [1, 2, 3, 4, 5]
  y = x.collect do |x|
    x ** 2
  end

x is protected by being named in the parameter list, so it isn't
overwritten. Again behaving as you expected.

The code is the same as it was before. It's just clearer when to pick
{}'s and when to pick do..end's.

Eg, if you want to write a closure that has state:

  clicks = 0
  gui.button.press do |button|
    clicks = clicks + 1
  end

will work just fine. If you wanted to do the same thing with {}'s, then
use an instance @var like any other method. This works as expected too.

  @clicks = 0
  gui.button.press {|button| @clicks = @clicks + 1 }
  p @clicks   # Can be accessed here

It's so clean, it has to be right! :)

-- 
  spwhite / chariot.net.au