In role Iterator§

See primary documentation in context for method pull-one

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 produce and return the next value if possible, or return the sentinel value IterationEnd if no more values could be produced.

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

As a more illustrative example of its use, here is a count down iterator along with a simplistic subroutine re-implementation of the for loop.

# works the same as (10 ... 1, 'lift off')
class CountDown does Iterator {
    has Int:D $!current = 10;

    method pull-one ( --> Mu ) {
        my $result = $!current--;
        if $result ==  0 { return 'lift off' }
        if $result == -1 { return IterationEnd }

        # calling .pull-one again after it returns IterationEnd is undefined
        if $result <= -2 {
            # so for fun we will give them nonsense data
            return (1..10).pick;
        }

        return $result;
    }
}

sub for( Iterable:D $sequence, &do --> Nil ) {
    my Iterator:D $iterator = $sequence.iterator;

    loop {
        # must bind the result so that =:= works
        my Mu $pulled := $iterator.pull-one;

        # always check the result and make sure that .pull-one
        # is not called again after it returns IterationEnd
        if $pulled =:= IterationEnd { last }

        do( $pulled );
    }
}

for( Seq.new(CountDown.new), &say );  # OUTPUT: «10␤9␤8␤7␤6␤5␤4␤3␤2␤1␤lift off␤»

It would be more idiomatic to use while or until, and a sigilless variable.

until IterationEnd =:= (my \pulled = $iterator.pull-one) {
    do( pulled );
}