In Ruby if you write this:
a = [1, 2, 3]
e = a.each
e.each do |x|
p x
end
e.each do |x|
p x
end
You get 1, 2, 3, 1, 2, 3 as output (with newlines in between).
In Crystal you just get 1, 2, 3.
I think Ruby’s behavior is a bit more intuitive. An iterator represents some state ready to be executed, and you can execute it as many times you want.
I see this as similar to Rails ActiveRecord. You can do:
# This represents the users with id > 5
users = User.where('id > 5')
# We can iterate them all
users.each do |x|
end
# And again if we want
users.each do |x|
end
That is, users is a computation ready to be executed, and it can be executed as many times as we want.
The thing is, Ruby also has next and rewind on their Enumerator. But calling next or rewind doesn’t affect what happens with each, map, to_a, etc.
However, I think mixing each with next is never done in practice: you either want internal iteration or external iteration.
So maybe we can bring back rewind to Iterator and let each do a rewind just before iterating. Rewinding shouldn’t be expensive…
Or any other way we can make this work?
It’s a small detail, but I think it would make things much more intuitive and fun to work with.