Making fibers enumerable

Hi,

Most of the Enumerable methods can be used for fiber based generators
if
Fiber is made enumerable.

class Fiber
include Enumerable
def each
loop { yield self.resume }
end
end

def fib_gen
Fiber.new {
a, b = 0, 1
while true
Fiber.yield a
a, b = b, a + b
end
}
end

Find the fibonacci number greater than 1000

fib_gen.find {|x| x > 1000 }

take first 10 fibonacci numbers

fib_gen.take 10

take_while numbers are smaller than 1000

fib_gen.take_while {|x| x < 1000 }

If it could be the default behavior, it would be very useful. Some
methods
won’t be applicable, particularly for non-terminating generators in
their
default incarnation viz. drop_while. It can either be re-written to
advance
the generator using Fiber#resume or it can be left upto the user to
handle
infinite sequences correctly.

If I understand correctly, writing generators was one of the purposes of
fibers. Why can’t fibers be made enumerable by default?

On Wed, May 18, 2011 at 9:39 AM, Rahul K. [email protected]
wrote:

end

the generator using Fiber#resume or it can be left upto the user to handle
infinite sequences correctly.

If I understand correctly, writing generators was one of the purposes of
fibers. Why can’t fibers be made enumerable by default?

I am not sure how that interacts with the original intent of Fibers:
their main purpose is to bring coroutines to Ruby.

How would your example look if there was another generation that you
wanted to do concurrently? Because for the single threaded generator
case there is already a tool: Enumerator.new. The example in the
documentation even uses Fibonacci Numbers as example. :slight_smile:

http://www.ruby-doc.org/core/classes/Enumerator.html#M000299

fib_gen = Enumerator.new { |y|
a = b = 1
loop {
y << a
a, b = b, a + b
}
}

Now you can do exactly the same as you did with your example

Find the fibonacci number greater than 1000

fib_gen.find {|x| x > 1000 }

take first 10 fibonacci numbers

fib_gen.take 10

take_while numbers are smaller than 1000

fib_gen.take_while {|x| x < 1000 }

For this Fiber would be the wrong tool.

Kind regards

robert

On Wed, 18 May 2011 20:12:43 +0900, Robert K. wrote:

y << a

take_while numbers are smaller than 1000

fib_gen.take_while {|x| x < 1000 }

For this Fiber would be the wrong tool.

The Enumerator.new uses Fibers internally. Check enumerator.c in the
sources;
besides that, how would you achieve the needed effect without
coroutines?

On Wed, May 18, 2011 at 2:14 PM, Peter Z. [email protected]
wrote:

a = b = 1

take first 10 fibonacci numbers

fib_gen.take 10

take_while numbers are smaller than 1000

fib_gen.take_while {|x| x < 1000 }

For this Fiber would be the wrong tool.

The Enumerator.new uses Fibers internally. Check enumerator.c in the
sources;

That’s an implementation detail of Enumerator. The point is that the
primary purpose of Fiber is to be able to build concurrency without
preemption but with manual control over when one task yields to
another task. Enumerator.new on the other hand is a tool for
generation of sequences of items which is precisely what the Fibonacci
example is all about. There is no concurrency.

besides that, how would you achieve the needed effect without coroutines?

class X
include Enumerable

Callback = Struct.new :code do
def <<(x)
code[x]
self
end
end

def initialize(&code)
@code = code
end

def each(&b)
cb = Callback.new b
@code[cb]
self
end
end

fib_gen = X.new { |y|
a = b = 1
loop {
y << a
a, b = b, a + b
}
}

Find the fibonacci number greater than 1000

p fib_gen.find {|x| x > 1000 }

take first 10 fibonacci numbers

p fib_gen.take 10

take_while numbers are smaller than 1000

p fib_gen.take_while {|x| x < 1000 }

Kind regards

robert

On Wed, May 18, 2011 at 8:50 AM, Rahul K. [email protected]
wrote:

Coroutine - Wikipedia

Right. But aren’t semi co-routines(don’t send data; just receive) used to
implement generators?

Ruby fibers can be either semi-coroutines or full co-routines. And
while replacing continuations as the basis for implementing generators
was certainly an important motivation for implementing fibers in Ruby,
that’s not the only thing fibers can do, and enumerability may not
make sense for other fibers. So, usually, Enumerator::Generator is
used for generators (though that uses Fiber behind the scenes) and
Fiber is used directly for other use cases.

On Wed, May 18, 2011 at 4:42 PM, Robert K.
[email protected]wrote:

If I understand correctly, writing generators was one of the purposes of
fibers. Why can’t fibers be made enumerable by default?

I am not sure how that interacts with the original intent of Fibers:
their main purpose is to bring coroutines to Ruby.

Coroutine - Wikipedia

Right. But aren’t semi co-routines(don’t send data; just receive) used
to
implement generators?

Oh, didn’t know about this - somehow “The Ruby P.ming Language”
doesn’t
mention it or I missed it. I simply translated my Python code to Ruby.

Thanks for the info Robert.