I’ve run into an unexpected (for me) issue recently. Consider the following example where a simple
struct is used as an
struct MyIter include Iterator(Int32) def initialize; @index = 0; end def next; @index == 5 ? stop : (@index += 1); end end
the important point is that it’s a
struct and that its current state is represented by a value type
@index. Now, the following code
MyIter.new.map do |i| MyIter.new.map do |j| j end end.flatten.to_a
enters an infinite loop. The reason is how the
flatten iterator is implemented: it manages the nested iterators in an array, thus copying the inner iterator. When it access the inner iterator to advance it, it does not actually modify that iterator but a copy of it (something like
next method will be called on a copy, not on the iterator stored in
@generators). Hence, the inner iterator will remain on its first element forever.
Of course, the problem vanishes if the iterator is a
class not a
struct or if its state is not represented by a value type.
In hindsight this is totally expected but it was pretty surprising to me (and took me some time to figure out what’s going on, in particular, because many iterators within the stdlib are implemented as
So the real question is: what should be done about this? Is this considered a bug? Should the implementation of
Flatten be changed? Should it be mentioned in docs (or is it already and I missed the hint?)? Am I the only one who has been surprised by this?