Hacker News new | past | comments | ask | show | jobs | submit login
Let’s get serious about ES6 generator functions (facebook.github.io)
112 points by jamesgpearce on Oct 22, 2013 | hide | past | favorite | 41 comments



Good 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

[2] https://github.com/Raynos/gens


Thanks for the links! I hope regenerator can make those projects work in environments beyond node.js.


Primary author here. Ask me anything!


Eric 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/itera...


Re: how hard, I've been working on it for... a while ;) 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/tes...


I'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!


I'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.


Very 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.


Exactly, the `wrapGenerator` function provides a small runtime that (among other things) handles uncaught exceptions: https://github.com/facebook/regenerator/blob/master/runtime/...


This 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 :)


Really agree with this. I've come to appreciate both the limitations and power of generators during the course of this project.


Do 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.


I 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.


Any 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 :))


Looks very cool, do you all generate source maps?


Not just yet, but that's on the roadmap for sure: https://github.com/facebook/regenerator/issues/18


Please, don't skip the last step and make sure that you test them, too!

http://fitzgeraldnick.com/weblog/51/

:)


Completely awesome. I was going to use Continuum just because I wanted generators client side, but it was too slow.

Thanks for doing this!


I 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.


While 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.


Have you looked into using Caja to sandbox?

https://developers.google.com/caja/docs/runningjavascript/


Yes. 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.


Nice. Would be good to contribute it to Traceur, as teams wanting to early-adopt ES6 will be using that!


Interesting 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.


Why is there not a like button, send button, or facebook comments anywhere on the announcement page?



Awwww shucks. I was being cheeky and now your response has disarmed my cynicism. I'm naked.


Is there any bound to the number of cases that might be generated in that switch?


This 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).


Are you planning on supporting .send()?


You can pass a value to .next(), which provides most of the value of .send().


Wow, this is really impressive! Kudos.


Thanks! Please let me know if/how you end up using it!


... this isn't reddit. Haha, jk good work on this.


You should make a browserify transform (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.



Thank 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-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 :)


Okay, tried it, and actually worked with the demo from that article! Yay.


This 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


I 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.


It 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!




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: