Project

General

Profile

Bug #7715

Lazy enumerators should want to stay lazy.

Added by marcandre (Marc-Andre Lafortune) over 7 years ago. Updated over 7 years ago.

Status:
Closed
Priority:
Normal
Target version:
ruby -v:
r38825
Backport:
[ruby-core:51510]

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 or each 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

Also available in: Atom PDF