Leo
Leo

Reputation: 2103

Enumerator new and yield

At ruby docs I found this piece of code:

fib = Enumerator.new do |y|
  a = b = 1
  loop do
    y << a
    a, b = b, a + b
  end
end

Thing is i cant understand what it does. In general it calculates fibonacci's numbers, but I have hard time understanding the details. What is y (Enumerator::Yielder)? The docs says nothing about it. What does << method do? (I know its yield alias). Why does infinite loop happen when y << a is removed?Thanks!

Upvotes: 5

Views: 1977

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Consider the following code:

fib = Enumerator.new do |y| 
  puts "Enter enumerator"
  a = b = 1 
  loop do
    puts "Inside loop"
    y << a
    puts "y: #{y.inspect}, a: #{a}, b: #{b}"
    a, b = b, a + b 
  end 
end
puts fib.take(5)

It prints:

# Enter enumerator
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 1, b: 1
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 1, b: 2
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 2, b: 3
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 3, b: 5
# Inside loop

# 1
# 1
# 2
# 3
# 5

Apparently, this output actually gives hints on all the question you’ve stated. Note, that we entered a yielder only once. Let’s dig into:

Why loop is infinite?

Because Fibonacci’s number sequence is infinite. This enumerator is intended to be used with Enumerable#take (see an example above.)

What is Enumerator::Yielder?

It is an abstraction. It’s method yield actually calls back the block of callee, passing a parameter as block parameters.

What does << method does?

Yields once. In other words, it calls back the caller code, passing it’s parameter to the caller’s block. In this particular example, it will call back each block, passing a from Yielder instance as block parameter (e as I named it there.)

Why does infinite loop happen when y << a is removed?

Because there are no yields happened. In my example, the callee will stop after yielding five (5 as parameter of take) times.

Upvotes: 5

Related Questions