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.
I agree its non-idiomatic. But, I don't think being non-idiomatic is sufficient for something to be considered "evil". When something behaves in an inconsistent or unexpected way, then it starts to approach "evil" territory. Although the term is a little hyperbolic for my taste.
Definitely true. Unfortunately, Rails scaffolds and early Ruby programming books propagated this as an acceptable alternative to using iterators, and we're still feeling a bit of the pain from it now.
It's nice that James managed to dig up some technical reasons that extend beyond the idiomatic argument, as it may help push along those who aren't moved merely by the "It's not the Ruby way" argument.
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.
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.
Comments
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.
I agree its non-idiomatic. But, I don't think being non-idiomatic is sufficient for something to be considered "evil". When something behaves in an inconsistent or unexpected way, then it starts to approach "evil" territory. Although the term is a little hyperbolic for my taste.
Definitely true. Unfortunately, Rails scaffolds and early Ruby programming books propagated this as an acceptable alternative to using iterators, and we're still feeling a bit of the pain from it now.
It's nice that James managed to dig up some technical reasons that extend beyond the idiomatic argument, as it may help push along those who aren't moved merely by the "It's not the Ruby way" argument.
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.
Doesn't the same logic suggest marking "nonstandard" C code with "gotos"?
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.