Hacker News new | past | comments | ask | show | jobs | submit login
Generator (yield keyword) support in CoffeeScript for Node.js (almostobsolete.net)
48 points by almost on July 21, 2013 | hide | past | web | favorite | 28 comments

Lovely work, and it looks like it wasn't too difficult to add:


If anyone wants to chime in on the pull request itself, input is welcome -- particularly about how to address the conflict with the usual "compiles to JavaScript that runs anywhere" ethos of CoffeeScript. If we're going to start moving past that, "yield" is a fine place to start.

There are going to be some bigger issues if you start targeting ES6, like the inconsistency between for/of in ES6 vs. CoffeeScript, differences in destructuring, semantic inconsistencies in classes, etc.

I'd be very interested to see a proposal for how to deal with that moving forward for CoffeeScript. Will CoffeeScript:

1) ignore new ES6 features that have syntactic overlap with existing CoffeeScript features

2) leave the existing syntax alone and create new syntax that targets the ES6 syntax (for/of means CoffeeScript for/of, while for/inside means ES6 for/of)

3) break backwards compatibility and release a CoffeeScript 2 that targets ES6 and doesn't use syntax that could conflict in the future

There may be another option, but I can't think of it. Knowing exactly which of these options CoffeeScript will take will give me a better understanding of the long-term viability of CoffeeScript.

    > Knowing exactly which of these options CoffeeScript will take 
    > will give me a better understanding of the long-term viability 
    > of CoffeeScript.
Mmm, nothing like the whiff of uncertainty on a summer evening ;) For starters, you needn't worry -- CoffeeScript already being a heavily forked open-source project, I'm sure there will be versions (whether Coco, Live, Iced, Gorilla, or perhaps a cutely named CoffeES6cript) that track each of the options you've listed.

But you asked about my proposal. I'm most interested in targeting the useful subset of JavaScript that runs across the popular JS platforms at any given moment -- not what may or may not exist in the future, but lives currently as a spec; and also not features that actually exist, but aren't essential (read, harmful, error-prone, nasty), like getters and setters, or E4X (in my opinion, natch).

So in general, what I'd like to see mainline CoffeeScript do, is adopt useful ES6, ES7, and ES8 features, as soon as they land in enough platforms/browsers to be widely useful (yield may be at this point already, or very soon), and to continue to try and find a pleasing minimalist syntax for writing and reading them. If this means taking the ES* syntax wholesale, that's fine. If it means minting a new (and hopefully, but arguably, nicer) syntax, that's fine too. And if it means breaking backwards compatibility, that's also alright, as the compiled lowest-common-denominator JS output will still be perfectly compatible with the new stuff.

Thankfully E4X doesn't actually exist anymore (as of FF 21) :)

Even if CoffeeScript doesn't support ES6 features it will still be a useful in the long term. I'm betting ES3 code generated by CoffeeScript will run fine in a ES6 runtime.

With that said, I'm happy to lose backwards compatibility in lieu of ES6 support. We've already seen forks like IcedCoffeeScript before.

It should be a major jump though, with a migration guide at least. It's similar to the 1.8.7 -> 1.9.2 jump. It's painful, ugly, but for the greater good.

I'd love to see #3. As a user of a language, moving targets are a hassle. It would be clear as day if it was stated that existing CS 1.0 === ES5 (or whatever), CS 2.0 == ES6. This unshackles those working on CS to really fundamentally take advantage of the new features. (Isn't this spirit what drove CS in the first place?)

Alternatively you could use fibers. We've been using them together with Common Node (https://github.com/olegp/common-node) at https://starthq.com with great success - running smoothly on an EC2 micro instance with 300+ concurrent users on site.

I have been quite interested in using fibres. I have concerns about compatibility with existing libraries, stability etc.

Could you point to some documentation/discussion/blogs/anything that addresses these concerns and provides decent examples of use?

Here's a talk I gave on the topic: http://vimeo.com/32507674 and here are the slides: http://www.slideshare.net/olegp/js-everywhere-2011

Feel free to message me on Twitter (@olegpodsechin) and I'd be happy to answer any questions you have.

Generators will be an ES6 feature, and therefore libraries written using generators and yield will run on both the server and in browsers.

For many use-cases, this is a good enough reason to use them.

In my experience there's very few libraries that would require generators that could run on both the server and in browsers.

Great idea. Generators are one of the features that still seperate coffeescript from python, in terms of productivity/elegance.

Still missing is a syntax to consume these generators, like in "for a in b" or "yield from"

Definitely agree with need for iteration syntax and yieldfrom keyword. The iteration syntax will probably have be something different than "for a in b" because that's already used for array-like iteration and adding another case would slow existing code down (all of which wouldn't be using it of course). For yieldfrom the code it needs to generate is something like this:

    var generator = g1(), result = {}, send;
    while(!result.done) {
        result = generator.send(send);
        send = yield result.value;

I would suggest "for a from b". If that only uses .next and .send, it might work with class instances too, like the iterator protocol in Python.

I've found one problem with that syntax: people use variables named "from" quite a lot in code already (including all over the coffeescript source)

Good idea, I'll see if I can add that.

I've almost got yieldfrom working...

"for of" is actively being added to V8. It should not be very long before it lands in V8 (and thus in Node). I don't like the idea of another keyword that at best acts exactly the same (or at worst acts subtly different).

CoffeeScript already has an of operator (like js in) and an in operator (array like iteration) neither of which could easily be made to both (I think). So we'd probably need a new name. Once "of" is in V8 we can compile to it directly though.

It's not clear to me how to compile directly to it without breaking CoffeeScript code that already uses for/of. Is the idea to break compatibility with existing CoffeeScript code?

See my longer question about this upthread.

I honestly don't know, this was just a quick hack this morning while I had a hangover :) I think it's good to have the conversation though!

I'm not current on what kind of compatibility coffeescript is trying to keep, but IE6 certainly not going to like the newer V8 features...

From the article:

> Update: I've created a PR [pull request] for CoffeeScript. I've also just added the yieldfrom keyword...

Maybe this update happened after your comment?

Yes, both updates happened after that comment. In fact that comment provided a little extra motivation for me to get those extra features done :)

Does this mean that the mere presence of the word `yield` turns a function into a generator? Is there any way to build a yield-less generator (say, a noop generator for an API that requires a generator)?

Yes it does.

If you did want a generator that didn't yield anything I guess you could write:

    myEmptyGen = ->
      yield if false
Which is pretty ugly, but it's not something I've needed to do often with generators (in Python at least)

Does this work when compiling code to run on the browser?

If not, how could you modify the Coffeescript compiler to make that happen? (Preferably without requiring browser makers to make any changes.)

It's possible using two techniques called continuation passing transform and trampolines[1]. The downside is that the produced code would be a bit ugly and one of coffeescript's selling points has always been that it produces sensible code.

[1]: http://en.m.wikipedia.org/wiki/Trampoline_(computing)

I just added yieldfrom (like yield* in ES6, includes the output of one generator in that of another) support in a separate branch:


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