Why do generator expressions return generators?

Jason Orendorff jason.orendorff at gmail.com
Fri Sep 6 16:46:18 PDT 2013

On Fri, Sep 6, 2013 at 10:59 AM, David Bruant <bruant.d at gmail.com> wrote:
> The presence of .next and .throw will be unnecessarily confusing to authors.

Well, if you need to explain generator comprehensions to someone, I
suggest saying something like:

> "It's just shorthand for a generator"

If we changed it, so that generator comprehensions were simply
iterators, then you could simply explain:

> "It works like a generator, but it gets desugared into an iterator, so there's this one method that you probably won't ever call directly anyway, that isn't there. Oh, what's desugaring? It's when one language feature is explained in terms of others. So for example (for (x of y) x+1) desugars into something like {_it: y[@@iterator](), next() { var st = this._it.next(); if (!st.done) return {value: st.value + 1, done: false}; return st; }}"

On second thought, maybe equivalences are not so confusing. Maybe
gratuitous inconsistencies are confusing.

I don't really see .throw() on a generator-expression as a "footgun"
either. It does exactly what the .throw() method does for any
user-defined generator, most of which, in practice, will just rethrow
the exception—which by happy coincidence is exactly what it says on
the label:

    gen.throw(exc);  // shockingly, this will often throw exc

People will probably be somewhat disoriented the first time they
encounter generator comprehensions anyway. Coroutines are a little
mind-bending. But throw() really has nothing to do with it. The fact
that these expressions produce an object that's exactly the same as
another language feature is not an obstacle. I expect it'll help.


More information about the es-discuss mailing list