Anonymous Generators ?
The FileReader
generator is yield-free. Seems like a bug in that code.
Yes, that's where I'm stuck.
Here are the few variations I tired :
function* FileReader(){
// Some stream code on node;
stream.on('data',yield function*(data) {
yield data;
});
}
function* FileReader(){
// Some stream code on node;
yield stream.on('data',function*(data) {
yield data;
});
}
function* FileReader(){
// Some stream code on node;
var res = ' ';
stream.on('data',function(data) {
res = data;
});
yield res;
}
Creating an iterator for the parent generators will not help to iterator over the nested/child anonymous generators?
Hemanth H.M wrote:
Yes, that's where I'm stuck.
Here are the few variations I tired :
function* FileReader(){ // Some stream code on node; stream.on('data',yield function*(data) { yield data; }); }
Please notice that stream.on, or any event emitter.on in Node.js, will set an event listener callback to be called later, the generator function activation in which you call stream.on will have returned already. You want to use something like task.js here. See taskjs.org.
Yes, I'm aware of taskjs.
So it's not a good idea to mix streams and generators!
Thanks :)
Hemanth H.M wrote:
Yes, I'm aware of taskjs.
So it's not a good idea to mix streams and generators!
No, it's important not to think yield from a generator function nested in another will yield from the outer one. That seems to be what you thought, in all the variations.
Passing a function as a "downward funarg", whether generator or not, means the callee or whatever code eventually does something with that funarg may not call it before control returns to the outer function's activation -- and returns from there.
Thinking about concurrency requires more than generators. Generators return iterators which can be used synchronously, or not. If you write async patterns, including callbacks or event listeners set by .on(), it's up to you to schedule things. This is not a fault of generators, or of streams (or of event emitters in general).
I was absolutely under that assumption.
Streams allow the event loop to run between iterations, unlike yield, that's where it gets tricky and converting a stream based logic to task.js isn't straight forward.
Hemanth H.M wrote:
Streams allow the event loop to run between iterations, unlike yield, that's where it gets tricky and converting a stream based logic to task.js isn't straight forward.
How about something like this?
spawn(function *() {
var gen = this.thread;
stream.on('data', function (data) {
gen.send(data);
});
console.log(yield gen.next());
});
Brendan Eich wrote:
How about something like this?
spawn(function *() { var gen = this.thread; stream.on('data', function (data) { gen.send(data); }); console.log(yield gen.next()); });
Sorry, a generator instance can't next itself, so that last statement should be:
console.log(yield undefined);
We just need to park the task before console.log is invoked, such that the data the listener receives is sent to the paused task's generator and becomes theactual argument to console.log.
Ah! Sweet :)
Makes sense of why send() method was implemented for generators.
Can this be a pattern in itself or is there any specific name for this paradigm ?
Hemanth H.M wrote:
Can this be a pattern in itself or is there any specific name for this paradigm ?
Python folks call it "coroutines" but it's not the canonical meaning of that word.
Having yield as an expression form rocks -- you can yield a value and then someone can send you the value of that yield expression.
Thank you, for making it clear :-)
Brendan Eich wrote:
console.log(yield undefined);
And in ES6 as amended, this should just be:
console.log(yield);
Yield (after return, but return is a statement form, of course -- yield is an expression form due to send) can have an operand on its right, or no operand (meaning yield undefined). Cc'ing Allen to double-check that the spec will say so.
On Dec 10, 2013, at 10:18 AM, Brendan Eich wrote:
Yield (after return, but return is a statement form, of course -- yield is an expression form due to send) can have an operand on its right, or no operand (meaning yield undefined). Cc'ing Allen to double-check that the spec will say so.
Already says it...
On Sunday, December 8, 2013, Hemanth H.M wrote:
Ah! Sweet :)
Makes sense of why send() method was implemented for generators.
send(value) was removed in favor of next(value)
Rick Waldron wrote:
send(value) was removed in favor of next(value)
Thanks for reminding me -- the SpiderMonkey (after Python) split of send from next reflects the evolution in Python of yield from a statement form into an expression form (to which one sends values), combined with Python's strict arity checking (next takes 0 args, send takes 1). At least, that's my understanding.
ES6 has no reason not to unify send with next, so we did -- along with axing StopIteration in favor of a functional (record returning) style, which engines will have to optimize (not hard, but nothing's free) to avoid allocation per user-coded iterator next().
function* FileReader(){ // Some stream code on node; stream.on('data',function*(data) { yield data; }); }
Now :
var reader = FileReader(); console.log(reader.next()); // Would say { value: undefined, done: true }
The question being, where will the anonymous function yield the results to ?
P.S : This might be an IRC question, but wanted dig bit deeper than just solving this issue.