Warning: This has little practical value. I just want to know what's going on.
I've come accross this line multiple times online:
return to_enum __method__ unless block_given?
I wanted to test it out and made a generator method with it (#1), then I tried without it and came up with an enumerator (#2). I was happy with that, thinking that's the way it should be done - though later I came up with a solution using #lazy (#3) which I think looks more elegant.
Can you guess which is fastest? To my surprise, #1 is the fastest, followed by #2 and #3!
To me, the first looks like a bit of a hack and has undesirable behavior such as stalling if you give it an empty block (rather than just throwing an error if a block is given).
My QUESTION is, what's the fastest way to do this? How come #1 is faster than #2, what am I missing? If my solutions are okay, which is objectively best?
Edit: Simpler example, was fizzbuzz before (http://pastebin.com/kXbbfxBc)
def method
return to_enum __method__ unless block_given?
n = 0
loop do
n += 1
yield n ** 2
end
end
enum = Enumerator.new do |yielder|
n = 0
loop do
n += 1
yielder.yield n ** 2
end
end
lazy = (1..Float::INFINITY).lazy.map do |n|
n ** 2
end
p method.take 50
p enum.take 50
p lazy.first 50
require 'benchmark/ips'
Benchmark.ips do |bm|
bm.report('Method'){ method.take 50 }
bm.report('Enumerator'){ enum.take 50 }
bm.report('Lazy'){ lazy.first 50 }
bm.compare!
end