On Tue, Aug 6, 2013 at 12:00 PM, Tim Caswell <t...@creationix.com> wrote:
> > > > On Mon, Aug 5, 2013 at 6:26 PM, Mikeal Rogers <mikeal.rog...@gmail.com>wrote: > >> >> On Aug 5, 2013, at 4:16PM, Jake Verbaten <rayn...@gmail.com> wrote: >> >> The only confusion is knowing whether your using generators for async >> flow control or whether your using them to generate iterators you iterate >> over. >> Once you learn to only use the first type in synchronous fashion and >> only use the second type in an asynchronous fashion the confusion goes away. >> >> >> This is *exactly* what I'm worried about. >> >> I'm trying to think about this not in the context of "all the code I >> write" but "all the code i use, and what they use, and what they use". >> >> If yield becomes a successful pattern a library user won't be aware of >> all the dependent generators it has, just like very few people are aware of >> their dependencies dependencies dependencies. Yet somehow all of the actors >> along this chain have to be sure they didn't use generators one way when I >> want to use them another way. >> >> This is very concerning. Patterns should enforce or at the very least >> visibly display the compatibility they offer so that actors can coordinate >> without active collaboration, this sounds like it depends on a bunch of >> people all agreeing about how their API should be used without any visible >> indicator stating such. >> >> One of two things will happen: >> >> * Most iterators will be used for async which means that very few people >> will write them in a way that i'm worry about >> OR >> * Most iterators won't be use for async which means mixing up the two >> cases will end in bugs *only* visible at scale. >> > > I'm not sure I understand the concern here. Could you show me a concrete > case where this is a problem? Generators are generators. They are not > magic. They are also never implicit in ES6. They are annoyingly explicit > which has the one good side effect of you will never accidentally get > suspended in disinterested code. (I assume this is why they were designed > this way) > > Lets go back to the callback case where sync and async code is mixed: > > var items = []; > array.forEach(function (item) { > items.push(item); > }); > assert.equal(array.length, items.length); > > In forEach, the callback is *always* synchronous. Or in other words, it > will call the callback *before* returning. When it does return, you can > know that it's done calling the callback and won't do it ever again. > > But what if I wrote Stream.prototype.forEach that iterated over a node > stream? > > var items = []; > stream.forEach(function (item) { > items.push(item); > }); > assert.equal(items.length, 0); > > In this case, the forEach function would be async, meaning it *always* > calls the callback after it returns. The code block that the assert lives > in will run to completion and some later turns of the event loop will > trigger the calls to the callback and mutate the shared state `items`. > > How are generators any worse than this? The only visual queue that state > may change at some later time is the function keyword. But *all* functions > in javascript use the function keyword. Sync and async. > > Generators are in an extremely similar boat to callbacks. They are > certainly no worse in terms of accidental state clobbering as far as I can > tell. They are even more explicit because the only function bodies that > are allowed to be suspended are ones marked with `function*`. That star is > plenty ugly and hard to miss. I'll bet your dev tools don't even support > it and most versions of linters will blow up at this point. > Just wanted to interject some good news here: JSHint has already been updated with support for generator functions, by setting the es6 flag to `true` :) Rick > Then on top of that, even within these specially marked generator bodies, > the only places you can be suspended and resumed are at the `yield` > keyword. You can't call a normal function that then yields for you. If > you want to delegate this to another function you have to call it using > delegating `yield*`, then that function body has to also be marked as a > generator body with the star. > > So the pattern of creating generators that yield promises or continuables > and then wrapping in a small helper library that waits for the promise or > continuable to resolve is not magic at all. It's extremely explicit. > > Compare: > > function insertFile(path, callback) { > fs.readFile(path, onFile); > > function onFile(err, data) { > if (err) return callback(err); > db.insert(data, callback); > } > } > > vs: > > function insertFile(path, callback) { > run(function* () { > var data = yield fs.readFile(path); > return yield db.insert(data); > }, callback); > } > > Both of which are consumed using: > > insertFile("myfile.txt", function (err, id) { > if (err) throw err; > console.log("id", id); > }); > > > Tell me which is easier to find the two places where your code will be > suspended waiting on some I/O to complete? > > I have been playing with these techniques for years now and while there > are dangers in some systems (like node's original promise.wait, lua's > coroutines, or node-fibers), the danger about accidental suspension does > not exist with es6 generators! > > If there is something I'm missing, please show it to me. I've been wrong > before on this list. ( > https://groups.google.com/d/msg/nodejs/eK00eDF-4Zw/FQhDrlEs0xUJ) > > -Tim Caswell > > > >> >> -Mikeal >> >> -- >> -- >> Job Board: http://jobs.nodejs.org/ >> Posting guidelines: >> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines >> You received this message because you are subscribed to the Google >> Groups "nodejs" group. >> To post to this group, send email to nodejs@googlegroups.com >> To unsubscribe from this group, send email to >> nodejs+unsubscr...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/nodejs?hl=en?hl=en >> >> --- >> You received this message because you are subscribed to the Google Groups >> "nodejs" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to nodejs+unsubscr...@googlegroups.com. >> For more options, visit https://groups.google.com/groups/opt_out. >> >> >> > > -- > -- > Job Board: http://jobs.nodejs.org/ > Posting guidelines: > https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines > You received this message because you are subscribed to the Google > Groups "nodejs" group. > To post to this group, send email to nodejs@googlegroups.com > To unsubscribe from this group, send email to > nodejs+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/nodejs?hl=en?hl=en > > --- > You received this message because you are subscribed to the Google Groups > "nodejs" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to nodejs+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- -- Job Board: http://jobs.nodejs.org/ Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines You received this message because you are subscribed to the Google Groups "nodejs" group. To post to this group, send email to nodejs@googlegroups.com To unsubscribe from this group, send email to nodejs+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/nodejs?hl=en?hl=en --- You received this message because you are subscribed to the Google Groups "nodejs" group. To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.