In article <f04d2210909251312q46bd51c0teacc4b0a8c417f0c / mail.gmail.com>,
  Charles Oliver Nutter <headius / headius.com> writes:

> So the small problem with Enumerator#next is that it's slow on MRI
> because of continuations and slow on JRuby because of native threads.

I thought this slowness sometimes ago.

STDIN.lines.next
is basically same as
STDIN.gets or raise StopIteration
but it has overhead of Fiber.

IO has already a method for external iteration method (gets)
but IO#lines cannot use it.

I think Enumerator.new (and possibly to_enum, enum_for)
should be able to take an array consists of two method names
for internal and external iteration as:
  Enumerator.new(obj, [method1, method2], *args)
method1 is for internal iteration and method2 is for
external iteration.  The enumerator created by
Enumerator.new uses method2 when next method is called if
method2 is provided.  obj.method2 should return an object
for external iteration. 

If Enumerator.new provides such way to avoid Fiber, IO can
use it as:

class IO
  def lines
    Enumerator.new self, [:each_line, :external_iterator_for_lines]
  end

  def to_enum(meth=:each, *args)
    if meth == :each || meth == :each_line
      super [:each_line, :external_iterator_for_lines], *args
    else
      super
    end
  end

  def external_iterator_for_lines
    o = Object.new
    o.instance_variable_set(:@io, self)
    def o.next
      @io.gets or raise StopIteration
    end
    o
  end
end

This idea may solve some part of JRuby problem if a class
provides custom to_enum.  If a class don't provide that or
user specify unexpected method name for to_enum, it still
problem though.
-- 
Tanaka Akira