On Wed, Jun 6, 2012 at 12:20 PM, Ivan Enderlin @ Hoa
<ivan.ender...@hoa-project.net> wrote:
> In addition to Gustavo's remarks, I wonder how the GC would collect a
> Generator object that is not use anymore (especially with a referenced
> yield). Does it fit to the current CG strategy or do we need an extra
> strategy? I would notice that the “Yield by reference” section does not
> exist but you have targeted it).
I added a new section which answers the question at least partially:
https://wiki.php.net/rfc/generators#closing_a_generator
If you don't need the generator object anymore you can either
explicitly ->close() it or wait until all references to it are removed
(typically when leaving the scope of the calling function). When the
generator is closed it releases all used resources, including the
suspended execution context and the currently yielded value. Whether
or not the value is yielded by reference shouldn't make a difference.
So, yes, the current GC strategy works well for generators too :)

> Moreover, I wonder how a “recursive yield” would act (something like “public
> function *f ( … ) { … yield $this->f(…); … }”). It is possible? Is it
> anticipated?
Your particular code would simply yield a generator object (as that's
what $this->f(…) returns).

If instead you wanted to yield all values from that object you could
wrap it in a foreach loop:

function *f() {
    // ...
    foreach ($this->f() as $value) {
        yield $value;
    }
    // ...
}

What this doesn't yet properly cover is the use of generators as
cofunctions. In this case it is desirable that ->send() calls are also
propagated (same applies to ->close() and the not yet implemented
->throw()).

To cover all those use-cases you'd have to come up with a rather big
and ugly block of code (you can find a Python same implementation in
http://www.python.org/dev/peps/pep-0380/#formal-semantics).

Thus it is clear that another expression is required which allows you
to delegate execution to another generator/cofunction. In Python this
is "yield from", in JavaScript "yield*".

A tree implementation using it could look like this:

class Tree implements IteratorAggregate {
    protected $value, $left, $right;

    public function __construct($value, Tree $left = null, Tree $right = null) {
        $this->value = $value;
        $this->left = $left;
        $this->right = $right;
    }

    function *getIterator() {
        if ($this->left) yield* $this->left;
        yield $this->value;
        if ($this->right) yield* $this->right;
    }
}

As you can see the iterator implementation is dead simple.

(Note though that the yield* expression described above isn't yet
implemented, but I plan to implement it.)

Nikita

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

Reply via email to