class Enumerator[out T]

include Enumerable[T]

An external iterator over what a method yields: xs.each, xs.map, xs.each_with_index, xs.each_slice(n), range.step(n) without a block return one. It is Enumerable, so xs.each_with_index.map { } works, and #with_index collects with an index (xs.map.with_index).

#next and #peek walk it one element at a time, from where the source is: an array, a hash or a set (or a builder, by index as it is then), an integer range (an endless one too) and Range#step, a String range, Int#times, Int#upto, Int#downto and Int#step, String#each_char, a subclass of Enumerator (below), and an enumerator over one of these (each_with_index, each_slice, each_cons, map, to_enum). A method written in Quarz has no such position: its enumerator raises NotImplementedError at #next, and its elements come through #each and the Enumerable methods only. #each and the Enumerable methods run the underlying method again from the start and do not move the position of #next. An enumerator is not Shareable: it stays in the task that made it.

A class of its own is an external iterator when it subclasses Enumerator and defines #next, raising StopIteration past the last element: #each, #with_index and the Enumerable methods then call its #next (from where it is), and #peek, #rewind and #size raise NotImplementedError unless it defines them too. Rewinding an enumerator also rewinds its source when that is an object defining rewind (such a subclass, say), as Ruby's does.

e = [1, 2].each
e.next   # => 1
e.peek   # => 2
e.next   # => 2
e.next   # raises StopIteration
e.rewind.next   # => 1
(1..).each.next   # => 1

class Countdown < Enumerator[Int]
  var @n: Int
  def initialize(@n: Int)
  end
  def next -> Int
    raise StopIteration, "done" if @n == 0
    @n -= 1
    @n + 1
  end
end
Countdown.new(3).to_a   # => [3, 2, 1]

<prelude>:3737

Methods

def each(&: (T) -> Void) -> Void

Calls the block with each element, by calling the underlying method from the start (leaving the position of #next as it is); a subclass's by its #next.

<prelude>:3746

def next -> T

The element at the position, and moves past it.

Raises

StopIteration past the last element; NotImplementedError for a source that is a method written in Quarz, and in a subclass that does not define it.

<prelude>:3754

def peek -> T

The element at the position, without moving past it: what #next would return.

Raises

As #next; NotImplementedError in a subclass that does not define it.

<prelude>:3762

def rewind -> Self

Moves back to the first element, and returns the enumerator.

Raises

NotImplementedError in a subclass that does not define it.

<prelude>:3768

def size -> Int

The number of elements. Iterates over them (an endless source never returns).

Raises

NotImplementedError in a subclass that does not define it.

<prelude>:3775

def with_index[U](&: (T, Int) -> U) -> Array[U]

Collects the block's results: xs.map.with_index { |x, i| ... }.

The index starts at offset (0 without one).

%w[a b].each.with_index(1) { |s, i| "#{i}. #{s}" }   # => ["1. a", "2. b"]

<prelude>:3783

def with_index[U](offset: Int, &: (T, Int) -> U) -> Array[U]

Collects the block's results: xs.map.with_index { |x, i| ... }.

The index starts at offset (0 without one).

%w[a b].each.with_index(1) { |s, i| "#{i}. #{s}" }   # => ["1. a", "2. b"]

<prelude>:3785