On Tue, Nov 04, 2008 at 03:41:27PM +0900, Yukihiro Matsumoto wrote:
> See [ruby-core:19691].  It's an issue with #next.

Thanks: I see that the 'next' API for calling enumerators is less powerful
compared to each { ...block... }, since the block can return a value.

But when does #inject actually depend on #next, rather than #each?

Let me see if I can explain what I'm trying to say. ISTM there are now
several ways you can write an iterator.

(1) The traditional iterator.

class Fib
def initialize(a=1,b=1)
@a, @b = a, b
end
def each
a, b = @a, @b
yield a
while true
yield b
a, b = b, a+b
end
end
end

# Simple call
Fib.new.each { |x| puts x }

# if you 'include Enumerable' in the class then you can also do
#   puts Fib.new.take(10)

# External iteration
fib = Fib.new.to_enum
while true; puts fib.next; end

# Enumerator is itself Enumerable
puts fib.take(10)

(2) The Enumerator block way.

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

# Simple call
puts fib.each { |x| puts x }

# External iteration
fib.rewind
while true; puts fib.next; end

(3) As a custom class which implements external iteration directly. These
are pretty ugly, as they're unlikely to be thread-safe.

class Fibber
def initialize(a=1, b=1)
@a1, @b1 = a, b
rewind
end
def rewind
@a, @b = @a1, @b1
end
def next
res = @a
@a, @b = @b, @a+@b
res
end
end

f = Fibber.new
10.times { puts f.next }
f.rewind
10.times { puts f.next }

# You can turn this into internal iteration; I don't know if there is
# a method for this in the core language already

def ext_to_int(ext_iterator)
Enumerator.new do |y|
ext_iterator.rewind
begin
while true
y << ext_iterator.next
end
rescue StopIteration
end
end
end

f2 = ext_to_int(f)
f2.each { |x| puts x }

Now, as you can see, it is possible to adapt the "each" pattern to the
"next" pattern, and vice versa.

Where I'm going is this: in what way does the Ruby core depend on the "next"
pattern? It may be useful for users to be able to *use* the "next" pattern
as a way of pulling values from an existing iterator.

But Enumerable#inject is a built-in Ruby method, and as far as I can see it
only needs to call 'each' on the underlying object. In the (unusual) case
that you had an external-only iteration object which you wished to call
#inject on, then you can wrap it as in example (3) above.

However, I feel that I have missed an important point entirely, and so I'd
be very happy to be enlightened on this.

Regards,

Brian.

P.S. I'm still missing the point of enumerators created from 'map' or
'select' without blocks.

a = (1..10)

b = a.select

# I believe this is the same as
b = a.to_enum(:select)

# Both execute b.each { ... } as a.select { ... }
# But why is this useful?