- Version: 0.42
- Date: 2018-03-04
- Author: Paul Crovella
- Status: Draft
- First Published at: https://gist.github.com/pcrov/d3e7048b4d002fbe71aeb91cb212361c
Generators reduce the boilerplate necessary to create iterators, this proposal aims to do the same for using generators outside of foreach
.
Ultimately this is sugar that allows you to take any generator and simply call it to get the next value.
Make generators callable such that each call returns the next yielded value. If a generator is given an argument when called it will
be the equivalent of calling send
. Without an argument it will be the equivalent of calling current
if the generator has not yet
yielded a value, or next
then current
if it has.
Generators would pass type checks for callable
, including is_callable()
.
In addition to reducing boilerplate this would mean you don't need to keep track of whether the generator has already yielded a
value in order to decide whether to call current
on it, or next
then current
. Another way to handle this is to always call
next
following current
, but you don't always want to immediately advance a generator through a potentially expensive operation,
plus it precludes send
ing should the need arise.
While it's possible to create an object in userland that behaves like this, it couldn't be a generator as Generator
is final.
Plus it wouldn't help with pre-existing generators - if you're wrapping a given generator there's no way to tell whether it's yielded
its first value already, and hence whether to call next
before current
.
Above all though it is sugar.
function countdown() {
yield 3;
yield 2;
yield 1;
}
$gen = countdown();
$gen(); // 3
$gen(); // 2
$gen(); // 1
$gen(); // NULL
would be equivalent to:
$gen->current(); // 3
$gen->next();
$gen->current(); // 2
$gen->next();
$gen->current(); // 1
$gen->next();
$gen->current(); // NULL
What to do when a return expression is reached?
function harumph() {
yield "Good day, sir!";
return "I SAID GOOD DAY, SIR!";
}
It behaves as calling current
- returns null. Further calls remain the same, returning null.
$gen = harumph();
$gen(); // Good day, sir!
$gen(); // NULL
It behaves as calling getReturn
- returning the value of the expression. Further calls remain the same, returning the value of the
expression.
A benefit of this is that if you're using this simplified interface you're probably not guarding with valid
everywhere, and this
would let you easily specify your own end-of-generator marker if your generator can otherwise yield null.
$gen = harumph();
$gen(); // Good day, sir!
$gen(); // I SAID GOOD DAY, SIR!
None. The existing interface remains and can be used in conjunction with this.
Unless there's some bit of code out there that specifically relies on generators not being callable, in which case yeah that breaks.
7.next
It may or may not be desirable to extend this to iterators in general. My name's Paul and that's between y'all.
A simple yes or no, requiring a 2/3 majority.
Looking for volunteers.
Somebody? Anybody?