some generator issues
Yuh-Ruey Chen
maian330 at gmail.com
Mon Apr 23 09:39:08 PDT 2007
Brendan Eich wrote:
> On Apr 22, 2007, at 9:04 PM, Yuh-Ruey Chen wrote:
>
> > Alternatively, we could make gen.next() and gen.send() special in that
> > they are already prebound to gen (e.g. gen.send.call(anotherGen) still
> > results in gen.send()).
>
> This is a possibility, but it would change the |this| binding inside
> the generator function from its initial value, captured when the
> generator function was called to create a geneator-iterator.
>
> The JS1.7 native methods for generators (next, send, etc.) throw if
> called on the wrong type of |this|, so it's conceivable that ES4
> could bind these methods to their generator-iterator and avoid such
> type errors. But what you propose above requires re-binding |this| in
> the saved execution context for the generator function, which is kept
> inside the generator-iterator.
>
> > Personally, I'd rather not do this - pretty much
> > all builtin classes have unbound prototype methods rather than bound
> > instance methods.
>
> Not all built-in classes have unbound prototype methods, and for good
> reason in certain cases. String and Array methods are intentionally
> generic, apart from to*String/valueOf -- those throw type errors if
> misappropriated.
>
> Class methods in ES4 are bound, so extracting a reference to one
> forms a binding with the object from which the method ref was
> extracted, supplying that object as |this| in subsequent calls via
> the ref.
>
> But the idea for generator next and send that the saved |this|, from
> the original activation of the generator function, would be replaced
> by the generator-iterator, is interesting. It provides the
> convenience Yuh-Ruey is seeking. On the other hand, it overwrites the
> |this| captured in the generator call. I think that's a fatal
> (barely) flaw.
>
> So still looking for a slick way to propagate the generator-iterator...
>
> /be
>
Replacing |this| is not what I'm suggesting - in fact, I rejected it for
the reason you give. |this| within the generator function is left
untouched - it's not replaced with anything. The generator-iterator is
accessed within the generator function via arguments.generator. Then I
proposed that next() and send() are bound class methods rather than
unbound prototype methods. I'm not exactly sure how class methods are
implemented, but in ES3, this is practically equivalent to:
// constructor for generator-iterators
function Generator(...) {
...
var self = this;
this.next = function() { return Generator.prototype.next.call(self); };
this.send = function(x) { return Generator.prototype.send.call(self,
x); };
...
}
...with the added benefit that Generator.prototype.send/next can still
be overwritten meaningfully. But as I said before, it seems odd that
only next() and send() are special, or that Generator (and possibly its
counterpart, Iterator) is special with respect to the builtin
constructors already in ES3.
In any case, I've been experimenting with Python lately to see if
there's some convenient solution for the intended use case (async calls
and returns), since Python's generator functions also lack a way to
access their "parent" generator-iterators. One library I've been looking
at is the Twisted framework, or rather it's Deferred component. It's
solution to this issue is an inlineCallbacks function intended to wrap a
generator function within some sort of generator manager:
http://twistedmatrix.com/documents/current/api/twisted.internet.defer.html#inlineCallbacks.
-Yuh-Ruey Chen
More information about the Es4-discuss
mailing list