Paul Philippov

Enumerable.each vs 'for' loops in Ruby

A few days ago I checked the code using the Ruby project roodi, and I received a warning saying “Don’t use ‘for’ loops. Use Enumerable.each instead.” I personally do not see any difference between these two versions of cycles, and attributed the problem of choice to issues of personal faith. I asked people in the Ruby group on identi.ca, but the answers were not convincing. Google also did not shed light on this question.

I changed the code to use Enumerable.each, just in case, and put the problem aside. But today, I found a sample code, that clearly demonstrates the difference:

loop1 = []
loop2 = []

calls = ["one", "two", "three"]

calls.each do |c|
  loop1 << Proc.new { puts c }
end

for c in calls
  loop2 << Proc.new { puts c }
end

loop1[1].call #=> "two"
loop2[1].call #=> "three"

Published on March 08, 2010 (over 10 years ago)

Article tags: loop, ruby

Comments (5)

ShadowBelmolve to Enumerable.each vs 'for' loops in Ruby

Strange...

loop1[1].call #=> "two"
loop2[1].call #=> "three"

ree 1.8.7

over 10 years ago

Paul Philippov to Enumerable.each vs 'for' loops in Ruby

Sorry. my fault, The original code had these values. I've simplified the code but overlooked the output in comments. I changed the post to have correct values.

over 10 years ago

Marty Andrews to Enumerable.each vs 'for' loops in Ruby

I wrote the Roodi check because Enumerable.each seems to be more idiomatic of Ruby code than for loops do. I commonly see people writing for loops when they're new to the language. For me, it *was* an issue of personal choice. People could always turn the check off if they don't like it.

I honestly wasn't aware of the differences you described above. Good to know though - thanks!

over 10 years ago

Paul Philippov to Enumerable.each vs 'for' loops in Ruby

Marty, thank you for the Roodi. The more I use it, the more I like it =)

over 10 years ago

Scott W. Bradley to Enumerable.each vs 'for' loops in Ruby

The difference is that #each scopes 'c' inside the block, whereas for/in scopes it outside the block. Your example is a bit tricky because of the indirection of the proc. In the #each case, each Proc has a different 'c' because that is scoped inside that block only. The for/in case, each Proc is sharing the same 'c' because it was scoped outside the loop -- hence they all get the value "three".

Another demonstration of this:

for i in [1,2,3]
# ...
end
puts i # => 3

[1,2,3].each do |j|
# ...
end
puts j # => NameError: undefined local...

almost 10 years ago