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.