7 ms·
Let’s get serious about ES6 generator functions
- bnjmn 13y agoPrimary author here. Ask me anything!
- acjohnson55 13y agoIs there any bound to the number of cases that might be generated in that switch?
- bnjmn 13y agoThis is hand-wavy for sure, but I don't think Emitter.prototype.emit is called more than once per AST node, and the number of cases should be less than the number of calls to .emit, so there should be fewer cases than AST nodes (which is a statically knowable number).
- TheTaytay 13y agoWow, this is really impressive! Kudos.
- bnjmn 13y agoThanks! Please let me know if/how you end up using it!
- jacabado 13y agoEric Lippert says the yield construct is the most complex of the C# language[1], how hard was it? I just tried a yield in a recursive function and the output is as simple as a non-recursive function. Are there any edge cases interesting to see? [1]http://blogs.msdn.com/b/ericlippert/archive/2009/08/24/iterator-blocks-part-seven-why-no-anonymous-iterators.aspx http://blogs.msdn.com/b/ericlippert/archive/2009/08/24/itera...
- bnjmn 13y agoRe: how hard, I've been working on it for... a while ;) https://twitter.com/benjamn/status/331923303767867392 https://twitter.com/benjamn/status/331923303767867392 Re: unforeseen edge cases, I'd love to see any failing pull requests for the test suite: https://github.com/facebook/regenerator/blob/master/test/tests.es6.js https://github.com/facebook/regenerator/blob/master/test/tes...
- PilateDeGuerre 13y agoWhy is there not a like button, send button, or facebook comments anywhere on the announcement page?
- deleted 13y ago[deleted]
- bnjmn 13y agoDone! Thanks! https://github.com/facebook/regenerator/commit/fe42c74a486fbe7fa1aac73d41a9d852939083a1 https://github.com/facebook/regenerator/commit/fe42c74a486fb...
- PilateDeGuerre 13y agoAwwww shucks. I was being cheeky and now your response has disarmed my cynicism. I'm naked.
- jlongster 13y agoI'd love a synopsis of the algorithm you use to do the transformation. I always thought it was possible but grew weary whenever I thought of having to transform everything (loops, etc) and keep the state. So glad to see that this was done!
- bnjmn 13y agoI'm hoping to do a more in-depth writeup about this soon, but the basic approach is to hoist all declarations up into the closure of an inner function, so that all variables in the scope of the function persist between .next calls, and then convert any control structures that contain yields to a big switch statement, where the cases are essentially jump targets, controlled by the $ctx.next property.
- jlongster 13y agoVery cool. I'm glad you went the whole way and transformed everything, including try/catch. I'm assuming it handles exceptions properly in the dynamic context? Take the following code: try { foo(); yield i; } catch(e) { console.log(e); } If `foo` throws an exception, I handle it, right? I don't see your generator wrapped in an exception handler, but maybe `wrapGenerator` does it.
- bnjmn 13y agoExactly, the `wrapGenerator` function provides a small runtime that (among other things) handles uncaught exceptions: https://github.com/facebook/regenerator/blob/master/runtime/dev.js https://github.com/facebook/regenerator/blob/master/runtime/...
- swannodette 13y agoLooks very cool, do you all generate source maps?
- bnjmn 13y agoNot just yet, but that's on the roadmap for sure: https://github.com/facebook/regenerator/issues/18 https://github.com/facebook/regenerator/issues/18
- mnemonik 13y agoPlease, don't skip the last step and make sure that you test them, too! http://fitzgeraldnick.com/weblog/51/ http://fitzgeraldnick.com/weblog/51/ :)
- apaprocki 13y agoDo you think it is worth the extra complexity of browser-detecting and loading the original JS if the browser has actual ES6 generator support? Firefox has it now without requiring any flags. Chrome(/Opera)/Node require --harmony or --harmony-generators.
- bnjmn 13y agoI might recommend against the additional complexity for most use cases, since the generated code is only 1.5x slower, but I fully expect/hope that Facebook will decide to bite that complexity bullet for the speed gains in newer browsers. Betting on the future of JS is very much the ethos here.
- apaprocki 13y agoAny interest at FB to sponsor the JSC implementation? That would leave IE as the odd one out... (If anyone reading works at Microsoft, politely ask the IE team to prioritize ES6 generators :))
- timruffles 13y agoNice. Would be good to contribute it to Traceur, as teams wanting to early-adopt ES6 will be using that!
- bnjmn 13y agoInteresting suggestion. Although Traceur's generator support is arguably more limited, I have to admit their code is currently better tested than regenerator's, so I think I want to give this repo some time to mature before exploring whether the Traceur team wants to use it.
- fzzzy 13y agoCompletely awesome. I was going to use Continuum just because I wanted generators client side, but it was too slow. Thanks for doing this!
- bnjmn 13y agoI love Continuum, and I think it takes the right approach for implementing all of ES6, if that's what you want. I just didn't think I could pitch the idea of using a virtual virtual machine to my team, so I took the more conservative approach.
- fzzzy 13y agoWhile I would love the rest of es6 the only things I really really want for the project I am working on are generators and sandboxes. I tried implementing sandboxing a little while back by cleaning the global namespace after every tick and freezing all the built in prototypes, but I still don't know enough about the dirty details of js to know if I am doing it properly in a way that will actually be fast. I am reluctant to use with but a friend of mine suggested that it is possible to use it to avoid polluting the global namespace. This in combination with freezing all the global prototypes might be enough to do what I want. Have you thought about this at all? Is there already a library for this that would do what I want? I wouldn't mind running the code in a worker to restrict access to the dom apis.
- apaprocki 13y agoHave you looked into using Caja to sandbox? https://developers.google.com/caja/docs/runningjavascript/ https://developers.google.com/caja/docs/runningjavascript/
- fzzzy 13y agoYes. Thanks for reminding me to look at it again though. I think it might be a little slower than I would like, but I will try again.
- anonymoushn 13y agoThis is pretty great. In the past I've had some awful things to say about generators as compared to more powerful control flow primitives, but this transformation highlights an advantage of generators. The transformed code is tiny and surprisingly readable. If someone wanted coroutines that could yield from subroutines, or (heaven forbid) shift+reset, this sort of transformation of basic-blocks-and-gotos into loops-and-cases would no longer be sufficient. Generators hit a sort of sweet spot. Thanks :)
- bnjmn 13y agoReally agree with this. I've come to appreciate both the limitations and power of generators during the course of this project.
- EricDeb 13y ago... this isn't reddit. Haha, jk good work on this.
- srhazi 13y agoAre you planning on supporting .send()?
- bnjmn 13y agoYou can pass a value to .next(), which provides most of the value of .send().
- shtylman 13y agoYou should make a browserify transform (https://github.com/substack/node-browserify https://github.com/substack/node-browserify) so that it can easily be put into a pipeline to convert generator code to es5 code. Folks using browserify will be able to use it very easily.
- bnjmn 13y agoGreat idea. Issue filed: https://github.com/facebook/regenerator/issues/20 https://github.com/facebook/regenerator/issues/20
- eldude 13y agoGood stuff. This will come in handy if node.js 0.12 takes much longer. Watching the use of generators in JavaScript and especially node.js is going to be very exciting over the coming years. We're excited at LinkedIn because we write a lot of node.js, and control flow is always being discussed: step, async, stepup, promises, and async generators look to solve a lot of that. Also, checkout the AGen formal spec[1] for asynchronous generators. Raynos and I put it together recently to encourage interoperability between async generator solutions, and we're both using it in personal projects.[2] [1] https://github.com/AsynchronousGenerators/agen-spec https://github.com/AsynchronousGenerators/agen-spec [2] https://github.com/Raynos/gens https://github.com/Raynos/gens
- bnjmn 13y agoThanks for the links! I hope regenerator can make those projects work in environments beyond node.js.
- jessep 13y agoThank you! This is so exciting. I've been wanting to try things like go style concurrency (http://swannodette.github.io/2013/08/24/es6-generators-and-csp/ http://swannodette.github.io/2013/08/24/es6-generators-and-c...) in the browser, and this seems like it will help us get there. Granted, haven't tried it yet, and really understand nothing about any of this, but ... Anyway, hooray :)
- jessep 13y agoOkay, tried it, and actually worked with the demo from that article! Yay.
- pornel 13y agoI couldn't find information why generator functions in JS require '*' in the syntax (ES6 spec/wiki just states this as a fact, but no rationale). Does anybody know? Python manages to work fine without ugly wart in the syntax, and it seems to me that presence of `yield` keyword in body is enough at syntactical level to tell compiler that the function is a generator.
- bnjmn 13y agoIt means you can have generator functions that contain no yield statements, which is not as crazy as it sounds. I've had to do `if False: yield` before in Python to trick the language into treating a function as a generator. An unyielding generator behaves so differently from a similar-looking non-generator function that the extra syntax seems more than appropriate to me. The asterisk also makes it trivial (using regular expressions) to tell whether a string of code contains any generator functions. "Explicit is better than implicit" is a rule of thumb that Python supposedly values, but neglects to follow here!
- zamalek 13y agoThis is similar to my asyncscript pet project[1] (that was met with much resistance on the Node.js mailing list as it was Yet Another CPS Framework). It drew inspiration from the way that C# creates the state machines for "yield" and "await". The project is dead (it only dealt with async calls and I never got round to "enumeration generators"), but if you are wondering how regenerator works I have a nice explanation at the bottom of readme.md. [1]: https://github.com/jcdickinson/asyncscript https://github.com/jcdickinson/asyncscript