Forever iterator - a good use of goto?

October 3, 2018   

I had a situation recently where I was required to iterate over an array contained by an object, forever. That is to say, that I would iterate for an variable number of array items (colours, as it happens) for and unknown number of times, until I’d finished.

I thought about using the SPL iterators, specifically, an InfiniteIterator around an ArrayIterator, like so:

1<?php
2
3public function getColours()
4{
5    return new \InfiniteIterator(new ArrayIterator($this->colours)); // where typeof($this->colours) == "array"
6}

This would work fine, but it occurred to me that this could be a good use of goto. I remember reading a github issue where someone submitted a PR to replace goto’s in a project, and the author of the library showed that the goto’s were in fact faster, and easily understood and read. I thought this might also fit the bill. Something like this:

1<?php
2
3public function getColours()
4{
5    start:
6    yield from $this->array;
7    goto start;
8}

I actually found the second is short and quite understandable, a fairly isolated and easy to use goto.

But, is it faster?

The SPL classes are written in C, and this situation might not match the one from that vague memory.

Quick and dirty benchmark script:

 1<?php
 2function benchmark(iterable $thing, int $iterations = 1000000)
 3{
 4    $iterationsDone = 0;
 5    $start = microtime(true);
 6    foreach ($thing as $value) {
 7        if (++$iterationsDone == $iterations) {
 8            break;
 9        }
10    }
11    $end = microtime(true);
12
13    print "time taken = ".($end-$start).PHP_EOL;
14}
15
16
17$array = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
18
19print "benchmark InfiniteIterator".PHP_EOL;
20benchmark(new \InfiniteIterator(new ArrayIterator($array)));
21
22function foreverIterator(array $array) {
23    start:
24    yield from $array;
25    goto start;
26}
27
28
29print "benchmark foreverIterator".PHP_EOL;
30benchmark(foreverIterator($array));

The result?

 1$ php test.php
 2benchmark InfiniteIterator
 3time taken = 0.14849281311035
 4benchmark foreverIterator
 5time taken = 0.038147926330566
 6
 7## Fin
 8
 9So there you have it. Incontrovertible evidence that the goto has a place in infinitely iterating an array in
10time-sensitive applications. Was this one? No! Of course not. It was still fun though?! ;)