External Iterators in Ruby 1.9 Core!

| 1 Comment

Ruby 1.9 has, for a while now, supported Enumerators. These are Enumerable objects returned by iterator methods when the methods are invoked with no blocks. Until recently, Enumerators were still internal, Ruby-style iterators that you invoke with each.

But that has changed. I haven't seen this discussed anywhere in English, but recent builds of Ruby 1.9 (my build is from August 17th) also define methods next and next? on Enumerator. These are Python-style (and Java-style) external iterators:

Update: 8/24/07: Matz has just removed the next? method. So you now have to be ready to catch StopIteration when using Enumerators. This means that the twine method below doesn't work anymore..

r = 1..3   # An enumerable object
e = r.each  # An enumerator object
e.next   # => 1
e.next # => 2
e.next # => 3
e.next # StopIteration exception raised

True external iterators make the age-old problem of parallel iteration in Ruby trivial to solve. Here are some examples:

def twine(*enumerables)
  enumerators = enumerables.map { |x| x.each }
  while not enumerators.empty?
    e = enumerators.shift
    if e.next?
      yield e.next
      enumerators << e
    end
  end
end

def braid(*enumerables)
  enumerators = enumerables.map { |x| x.each }
  begin
    loop do
      values = enumerators.map {|x| x.next }
      yield *values
    end
  rescue StopIteration
    # This is normal termination condition
  end
end

a = [1,2,3]
b = [4,5,6]
twine(a,b,'a'..'b') { |x| puts x }
braid(a,b,7..10) { |x,y,z| print "#{x},#{y},#{z}\n" }

It appears that these new external iterators are not build on the old Generator library which used continuations (I think). Instead, they use a new Fiber class (a kind of micro-thread). It is not documented yet, but its in there in recent 1.9 builds. If you know how to use Fiber, feel free to explain in the comments.

1 Comment

hi david,

fiber : this reminds me of Win32 fiber's (http://msdn2.microsoft.com/en-us/library/ms682661.aspx)

Win32 implements fibers in the user space . They don't have a kernel stack(datastructure) of their own.

BR,
~A

The following functions are used with fibers.
Function Description
ConvertFiberToThread Converts the current fiber into a thread.
ConvertThreadToFiber Converts the current thread into a fiber.
ConvertThreadToFiberEx Converts the current thread into a fiber.
CreateFiber Allocates a fiber object, assigns it a stack, and sets up execution "to" begin at the specified start address.
CreateFiberEx Allocates a fiber object, assigns it a stack, and sets up execution "to" begin at the specified start address.
DeleteFiber Deletes an existing fiber.
FiberProc An application-defined function used with the CreateFiber function.
FlsAlloc Allocates a fiber local storage (FLS) index.
FlsFree Releases an FLS index.
FlsGetValue Retrieves the value in the calling fiber's FLS slot for a specified FLS index.
FlsSetValue Stores a value in the calling fiber's FLS slot for a specified FLS index.
IsThreadAFiber Determines whether the current thread is a fiber.
SwitchToFiber Schedules a fiber.

Books

Comprehensive coverage of Ruby 1.8 and 1.9

"The New Most Important Ruby Book"
Peter Cooper,
rubyinside.com

Completely updated for Ajax and Web 2.0

"A must-have reference"
Brendan Eich,
creator of JavaScript

The classic Java quick-reference

Advertising

Pages

Hosted By

Powered by Movable Type 4.21-en