On Thu, 7 Jun 2012 01:10:52 +0200, Nikita Popov wrote:
current() and key() should return false when !valid()
Are you sure about that? The Iterator::current() docs don't specify
anything, but the Iterator::key() docs say that it should return NULL
on failure. Checking on the first spl class that came to my mind
SplFixedArray also returns NULL when it is out of elements.
My bad. I was under the impression the semantics were similar to those
of next(), key(), etc. Instead the docs say under current() that the
function can return anything, under key) that it returns NULL on failure
(and issues an E_NOTICE) and for next() that "the return value is
ignored" -- whatever that means; I'll interpret it as saying anything
can be returned. I'm not sure how correct this documentation is, though.
next() is underspecified.
Not sure what exactly you mean. next() really doesn't do much more
than resuming the generator. What should I add additionally about it?
Sorry for not having been clearer. I mean you say "Resumes the
generator (unless the generator is already closed)", but you don't
specify what it returns (though apparently Iterator does not re
valid() refers to a section that doesn't exist.
Yes, sorry, I hadn't yet written it. I now added it at
https://wiki.php.net/rfc/generators#closing_a_generator.
And if you cannot implement rewind(), doing nothing is not an
option.
I was thinking of the Generator as a NoRewindIterator, which also
simply does nothing when rewind() is called on it. This allows you to
start traversing the iterator in one loop and continue traversing it
in another loop:
function *allNaturalNumbers() {
for ($i = 0; ; ++$i) {
yield $n;
}
}
$numbers = allNaturalNumbers();
echo 'First loop:', "\n";
foreach ($numbers as $n) {
echo $n, "\n";
if ($n == 3) break;
}
echo 'Second loop:', "\n";
foreach ($numbers as $n) {
echo $n, "\n";
if ($n == 6) break;
}
This would output:
First loop:
1
2
3
Second loop:
4
5
6
Generators in Python behave the same way. (To be fair though Python
generally has no notion of rewinding an iterator, so all
iterators in Python act like that.)
I don't know whether that behavior is of any use, so I'll gladly
change the behavior to throwing an exception if that's more
desirable.
In fact, if you can't implement Iterator in full, you should
implement Traversable instead.
Not sure whether the lack of rewinding behavior really disqualifies
it
to use the Iterator interface. I think having the internal iteration
methods exposed is quite handy, especially if you consider their use
as coroutines, where you often want to call the iteration interface
manually and not using a foreach loop.
RewindableGenerator could perhaps implement Iterator though -- but I
find
the nature of RewindableGenerator very strange. Whether an iterator
is
rewindable or not seems to be related to the nature of the generator
(e.g.,
is it reading packets from the network). It's not something you can
wrap a
non-rewindable generator and expect it to work. So it's a sort of
unsafe
operation, like a cast in C.
Yes, agree with that.
* Overall, the RFC is very underspecified. We never have a formal
description of what a generator is and exact semantics of it. There
is no
reference to exceptions. What to do if the generator returns
function. If
the generator can be a function method.
Yes, the RFC is only a stub, it's not complete yet. But to answer
your
questions:
* Exceptions can be thrown from generators as always.
* Not sure what you mean by "generator returns function". What would
be that problem with that?
* Generators can be methods, as shown in the example in the
Introduction section. Closures can also be generators.
I suppose this is a work in progress and that you just want to gauge
the
general interest, and I hope you take these considerations into
account.
Yup, thanks for your comments!
Nikita
--
Gustavo Lopes
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php