Bug #7715
closedLazy enumerators should want to stay lazy.
Description
I'm just waking up to the fact that many methods turn a lazy enumerator in a non-lazy one.
Here's an example from Benoit Daloze in [ruby-core:44151]:
lines = File.foreach('a_very_large_file').lazy
.select {|line| line.length < 10 }
.map {|line| line.chomp!; line }
.each_slice(3)
.map {|lines| lines.join(';').downcase }
.take_while {|line| line.length > 20 }
That code will produce the right result but will read the whole file, which is not what is desired
Indeed, each_slice
currently does not return a lazy enumerator :-(
To make the above code as intended, one must call .lazy
right after the each_slice(3)
. I feel this is dangerous and counter intuitive.
Is there a valid reason for this behavior? Otherwise, I would like us to consider returning a lazy enumerator for the following methods:
(when called without a block)
each_with_object
each_with_index
each_slice
each_entry
each_cons
(always)
chunk
slice_before
The arguments are:
- fail early (much easier to realize one needs to call a final
force
,to_a
oreach
than realizing that a lazy enumerator chain isn't actually lazy) - easier to remember (every method normally returning an enumerator returns a lazy enumerator). basically this makes Lazy covariant
- I'd expect that if you get lazy at some point, you typically want to remain lazy until the very end