

Evils of the For Loop in Ruby - wolfish
http://blog.grayproductions.net/articles/the_evils_of_the_for_loop

======
tptacek
This is interesting, but kind of besides the point. What makes "for" evil in
Ruby code is that it's non-idiomatic. A custom block "iterator" covers every
case where you might use "for", and more elegantly. In 116,000 lines of Ruby
code in our "toolshed" directory, I count _zero_ uses of it; almost none of it
is web code, and all our developers are ex-Pythonistas.

~~~
codeodor
What about cases where you want to illustrate that the something being done is
not "standard" -- to provide an extra hint.

Either way, there is at least one case where the custom block iterator doesn't
cover the usage of "for" - where you need the variables outside the scope of
the loop.

~~~
tptacek
Doesn't the same logic suggest marking "nonstandard" C code with "gotos"?

~~~
codeodor
It's a good question, but I'd have to say: only if you equate "nonstandard"
with "considered harmful."

Needless to say, I don't.

For one, there is a large difference between the spaghetti code that can
result from liberal and injudicious goto usage vs. whatever you might
encounter by using "for" instead of ".each"

In the goto case - we use it all the time under different names with special
circumstances: method calls, loops, breaks, nexts, etc.

In the case of for vs. each - it depends. In some cases you may indeed be
iterating over the contents of some object in particular. But what if you are
iterating over the contents of two disparate objects? Should we use ".each" on
one and keep a separate counter for the other?

And then, there are those times when you actually want the variables in the
loop to be available outside the scope of the loop, as I mentioned in the
previous comment. It might not be standard, but it does happen. One instance
is where you are letting doing evals on variables introduced by the objects in
the loop. That just can't happen with the .each call, and you need the "for"
loop to do it.

And I would add, even if it were possible to keep track of that in a block we
pass to #each, I would rather not do so because of the psychological
implications of doing so. If I want to iterate over two disparate objects, I
need a way of expressing that, and the "for" loop is it.

------
mattmcknight
It doesn't seem evil to me at all, it is exactly what I would expect.

    
    
      a = 1
      for a in 1..2
        b = a
      end
      p a
      >> 2
    

It seems natural that that would change the value of "a", I wouldn't expect a
for loop to create a new scoping context. The example with putting a closure
into the array is also what I would expect.

I am not sure what programming language has the scoping rules he expects, but
for me there's nothing to see here, moving along...

~~~
sandal
Ruby has block local scoping.

It's not the case where you set a beforehand that matters, but when you don't.

For example:

    
    
      >> (1..2).each { |i| p i }
      1
      2
      => 1..2
      >> i
      NameError: undefined local variable or method `i'
    
      >> for i in 1..2; p i; end
      1
      2
      => 1..2
      >> i
      => 2
    

So the real danger comes in here:

    
    
      >> procs = []
      => []
      >> (1..2).each { |i| procs << lambda { i } }
      => 1..2
      >> procs.map { |e| e.call }
      => [1, 2]
      >> procs2 = []
      => []
    
      >> for i in 1..2; procs2 << lambda { i }; end
      => 1..2
      >> procs2.map { |e| e.call }
      => [2, 2]
    

Which seems better to you?

If you're not coming from Ruby, I can understand how reading the first part of
this entry might make you think "what's the big deal", but if you read on,
you'll see an extended version of what I've shown above.

It's the closures that make this issue complicated.

~~~
mattmcknight
It's the Ruby 1.9 each implementation that seems confusing to me. I don't have
a natural feeling about a new scope being created for local variables first
referenced in that block. I am much more used to method, object, and class
level scoping. In most of the simple Ruby code I write, you can tell the scope
of a variable by looking at it's name. I can see where you might need the
block scoping with closures, but I actually find the second example more
logical. In the first example, I can't imagine which memory address would
still be holding the 1, and what it's name would be. I can easily see how the
value at i would be 2.

------
lysium
I don't get it. Isn't `|i|` the shorthand version of a lambda binding an i?
And `lambda { i }` a lambda not binding anything? So why is the result
surprising? I must be missing something.

Edit: I mean in

    
    
      each { |i| p i }
    

the |i| stands for a shorthand lambda, that binds an i.

And in

    
    
        for i in 1..3
          p i
        end
    

there is no such binding. So where's the problem? That 'for' should use a
lambda?

------
pkulak
Isn't that what _all_ languages do with a for loop? Why should Ruby break the
mold here?

------
omouse
So syntax is to blame once again...

