role Iterator

Generic API for producing a sequence of values

constant IterationEnd
role Iterator { }

A Iterator is an object that can generate or provide elements of a sequence. Users usually don't have to care about iterators, their usage is hidden behind iteration APIs such as for @list { }, map, grep and list indexing with .[$idx].

Iterators generally only allow one iteration over the sequence; afterwards they are exhausted.

The main API is the pull-one method, which either returns the next value, or the sentinel value IterationEnd if no more elements are available. Each class implementing Iterator must provide a pull-one method. All other Iterator API methods can be implemented in terms of pull-one, but also overridden for performance reasons.

Note: The only valid use of the sentinel value IterationEnd in a program is identity comparison (using =:=) with the result of a method in the iterator API. Any other behavior is undefined and implementation dependent.

Methods

method pull-one

Defined as:

method pull-one(Iterator:D: --> Mu)

This method stub ensures that classes implementing the Iterator role provide a method named pull-one.

The pull-one method is supposed to return the next value if available, or the sentinel value IterationEnd if no more elements are available.

my $i = (1 .. 3).iterator;
say $i.pull-one# OUTPUT: «1␤» 
say $i.pull-one# OUTPUT: «2␤» 
say $i.pull-one# OUTPUT: «3␤» 
dd $i.pull-one;  # IterationEnd 

method push-exactly

Defined as:

method push-exactly(Iterator:D: $targetint $count --> Mu)

Produces $count elements, and for each of them, calls $target.push($value).

If fewer than $count elements are available from the iterator, it returns the sentinel value IterationEnd. Otherwise it returns $count.

my @array;
say (1 .. Inf).iterator.push-exactly(@array3); # OUTPUT: «3␤» 
say @array# [1 2 3] 

method push-at-least

Defined as:

method push-at-least(Iterator:D: $targetint $count --> Mu)

Produces at least $count elements, and for each of them, calls $target.push($value).

If fewer than $count elements are available from the iterator, it returns the sentinel value IterationEnd. Otherwise it returns $count.

Iterators with side effects should produce exactly $count elements; iterators without side effects (such as Range iterators) can produce more elements to achieve better performance.

my @array;
say (1 .. Inf).iterator.push-at-least(@array10); # OUTPUT: «10␤» 
say @array# [1 2 3 4 5 6 7 8 9 10] 

method push-all

Defined as:

method push-all(Iterator:D: $target)

Produces all elements from the iterator and pushes them to $target.

The fallback is implemented in terms of repeated push-at-least with a large $count.

my @array;
say (1 .. 1000).iterator.push-all(@array); # All 1000 values are pushed 

method push-until-lazy

Defined as:

method push-until-lazy(Iterator:D: $target --> Mu)

Produces values until it considers itself to be lazy, and pushes them onto $target.

This matters mostly for iterators that have other iterators embedded, some of which might be lazy, while others aren't.

method is-lazy

Defined as:

method is-lazy(Iterator:D: --> Bool:D)

Returns True for iterators that consider themselves lazy, and False otherwise.

Built-in operations that know that they can produce infinitely many values return True here, for example (1..6).roll(*).

say (1 .. 100).is-lazy# OUTPUT: «False␤» 
say (1 .. Inf).is-lazy# OUTPUT: «True␤» 

method sink-all

Defined as:

method sink-all(Iterator:D:)

Exhausts the iterator (while discarding generated elements) purely for the side effects of the iteration.

say (1 .. 1000).iterator.sink-all;

method skip-one

Defined as:

method skip-one(Iterator:D: $target --> Mu)

Skips one value. The return value is truthy if skip was successful and falsy if there were no values to skip:

my $i = <a b>.iterator;
say $i.skip-onesay $i.pull-onesay $i.skip-one
# OUTPUT: «1␤b␤0␤» 

method skip-at-least

Defined as:

method skip-at-least(Iterator:D: $targetint $to-skip --> Mu)

Skips $to-skip values. The return value is truthy if skip was successful and falsy if there were not enough values to skip:

my $i = <a b c>.iterator;
say $i.skip-at-least(2); say $i.pull-onesay $i.skip-at-least(20);
# OUTPUT: «1␤c␤0␤» 

method skip-at-least-pull-one

Defined as:

method skip-at-least-pull-one(Iterator:D: $targetint $to-skip --> Mu)

Skips $to-skip values and pulls the next value. The returns the pulled value or IterationEnd if there were not enough values:

my $i = <a b c>.iterator;
say $i.skip-at-least-pull-one(2);
say $i.skip-at-least-pull-one(20=:= IterationEnd;
# OUTPUT: «c␤True␤» 

Type graph

Type relations for Iterator
perl6-type-graph Iterator Iterator

Stand-alone image: vector