Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why aren't Enumerators in Ruby (2.0 +) lazy by default?

Tags:

ruby

ruby-2.0

Why don't Ruby Enumerator behave like Enumerator::Lazy by default?

Is there any case where someone would want use a non-lazy Enumerator?

Edited:

A comment to backward compatibility answers below, explaining why I'm not yet convinced:

Say we had added these 'breaking' changes to Ruby 2.0.0, which is a major version, you would test your code (especially if you're going to production) thoroughly before making the switch, no?

Edit#2

I suspected it has to do with efficiency (let me know if anything is wrong), so I did the following benchmark: (of course there are places where lazy is better. this is to demonstrate, potentially, why Ruby is not using lazy all the time?)

require 'fruity'
require 'prime'

compare do
  lazy { 
    g = Prime::EratosthenesGenerator.new; 1000.times { g.lazy.take(100).to_a } 
  }
  diligent { 
    g = Prime::EratosthenesGenerator.new; 1000.times { g.take(100).to_a } 
  }
end

I get the following: (maybe due to the calling of .lazy method instead of using Enumerator::Lazy from the beginning?)

diligent is faster than lazy by 19.999999999999996% ± 1.0%
like image 415
Abdo Avatar asked Feb 13 '14 19:02

Abdo


People also ask

What does the lazy method do to enumerators and why is that useful?

Enumerator::Lazy is a special type of Enumerator , that allows constructing chains of operations without evaluating them immediately, and evaluating values on as-needed basis. In order to do so it redefines most of Enumerable methods so that they just construct another lazy enumerator.

What is enumerator in Ruby?

Enumerator, specifically, is a class in Ruby that allows both types of iterations – external and internal. Internal iteration refers to the form of iteration which is controlled by the class in question, while external iteration means that the environment or the client controls the way iteration is performed.


2 Answers

Make laziness the default would be a breaking change for any code that expects/relies on side-effects.

Any previous usage of Enumerator would need to be examined and tested. The "safest"/"sane" approach is simply to keep the non-lazy behavior as the default - while providing a Lazy alternative.

Some fundamental/previous design decisions are not so easily discarded; Enumerators are supported as far back as Ruby 1.8.7.

like image 149
user2864740 Avatar answered Sep 19 '22 20:09

user2864740


Probably for compatibility. Lazy enumerators were introduced recently, and many code depend on enumerators being non-lazy.

like image 27
sawa Avatar answered Sep 18 '22 20:09

sawa