On Tue, Nov 04, 2008 at 08:59:08PM +0900, Brian Candler wrote:
> But when does #inject actually depend on #next, rather than #each?

Also: if I am reading enumerator.c correctly, it seems that #next is
implemented as a layer on top of #each (by creating a fiber which in turn
calls #each).

So would it be true to say that 'each' is the fundamental behaviour of an
Enumerator - they would still work even if 'next' were not there?

I haven't quite worked out how the block form of enumerator works internally
though:

  class Enumerator
    def filter(&blk)
      Enumerator.new do |y|
        each do |*input|
          blk.call(y, *input)
        end
      end
    end
  end

  (1..10).to_enum.
    filter { |y,e| puts "Sending #{e.inspect}"; y << e; puts "Sent" }.
    filter { |y,e| y << e if e % 2 == 0; sleep 0.5 }.
    filter { |y,e| y << e + 100; sleep 0.5 }.
    each { |e| puts e }

I thought at first there must be Fibers involved somewhere, but now I think
it's just yielding: A yields value to B, B yields value to C etc. It's
very clever anyway :-)

Maybe it would be clearer if the Yielder object implemented #call and #[],
like a Proc.

Thanks,

Brian.