Hi Nikita,

On 26 February 2020 11:47:14 GMT+00:00, Nikita Popov
<nikita....@gmail.com> wrote:
>There is a relatively simple (at least conceptually) way to make generators
>rewindable: Remember the original arguments of the function, and basically
>"re-invoke" it on rewind().

This is an interesting idea.

There is a gotcha though, neatly demonstrated by your example:

>function map(callable $function, iterable $iterable): \Iterator {
>    foreach ($iterable as $key => $value) {
>        yield $key => $function($value);
>    }
>}

If the $iterable passed in is anything other than an array,
re-invoking the function won't actually rewind it. That can be fixed
by explicitly rewinding at the start:

function map(callable $function, iterable $iterable): \Iterator {
    reset($iterable);
    foreach ($iterable as $key => $value) {
        yield $key => $function($value);
    }
}

But now we have a different problem: if we pass an iterator that
doesn't support rewinding, we'll get an error immediately.


In other cases, the side-effects of running the "constructor" itself
might be undesirable. For instance, it might re-run an SQL query,
rather than rewinding a cursor:

public function getResultsIterator($sql) {
     $cursor = $this->runQuery($sql);
     foreach ( $cursor->getNext() as $row ) {
         yield $this->formatRow($row);
     }
}

I think the fix would be to return a generator rather than yielding
directly, like this:

public function getResultsIterator($sql) {
     $generator = function($cursor) {
         $cursor->rewind();
         foreach ( $cursor->getNext() as $row ) {
             yield $this->formatRow($row);
        }
     };
     $cursor = $this->runQuery($sql);
     return $generator($cursor);
}


In general, it feels like it would be useful for generators that knew
it was going to happen, but a foot-gun for generators that weren't
expecting it, so I like Judah's suggestion of an opt-in mechanism of
some sort.


Regards,
--
Rowan Tommins
[IMSoP]

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to