A syntax alternative for generators

Brendan Eich brendan at mozilla.com
Wed Sep 12 05:00:21 PDT 2012


Allen Wirfs-Brock wrote:
> The initializing generator arguments thread and related discussions 
> has got me questioning our use of function declaration/expression 
> syntax as our basis for defining generators.  Changing this would be a 
> departure from what Firefox has supported in recent years, but in ES6 
> we have more constructs to build upon than FF did in 2006. The 
> conclusion I reach is that it might be better to build generator 
> definition upon a foundation of arrow functions rather than classic JS 
> function definitions.

I strongly believe we should *not* go off into uncharted (as in 
unprototyped and not user-tested, or based on established work in other 
languages) territory.

There's nothing wrong with using function* (and much right) for 
generators, compared to alternatives we've already discussed. We can't 
add a new keyword even with newline sensitivity, and preserve the 
ability to write generator function expressions. Programmers who know 
Python don't want a new keyword. And arrows are not binding forms, while 
generators generally (but not always) want to be function declarations.

>   * If a generator needs to capture creation time state  it needs to
>     be wrapped in a factory function/method, similar to Brendan's
>     example above.

I'll be blunt here. You are making up something that is not common 
enough to impair generators in Python or JS1.7+. We have many years of 
experience with these languages. This contrived or a-priori worry needs 
evidence to motivate disrupting ES6 plans, at this point.

>   * If the factory is a method the wrapping creates confusion about
>     this/super binding.  For example:
>
> class MyClass {
>    dataSnapshot(aCollection) {
>         let snapshot = aCollection.clone();
>         return function*() {
>                for (let i = 0; i < snapshot.length; i++){
>                     yield thls.doSomething(snapshot[i]); //this is not 
> what was probably expected, super would be illegal
>                }
>          }();
>     }
> }

That's JS: you have to bind |this| one way or another, just as for any 
inner function. There is nothing new here.

Indeed trying to make generators different from functions just makes for 
more non-compositionality. Or assuming this must be the outer |this| 
just assumes the arrow conclution. Again it is very rare to write a 
nested generator this way, just to have a prolog that takes a snapshot. 
Here's a better collection example:

   function collectionIterator(aCollection) {
     for (let i = 0; i < aCollection.length; i++)
       yield aCollection[i];
   }

   function snapshot(aMutableCollection) {
     return collectionIterator(aMutableCollection.clone());
   }

By removing the contrived nesting and declaring a reusable 
collectionIterator, separating concerns, the gravamen of your complaint 
goes away.

>   * Generator function definitions need to be called to create an
>     actual iterator object (a generator instance)

This is a feature, don't break it.

>   * It is likely that a common error will be forgetting the invocation
>     of the generator in return statements such as the above.

Contrived code has contrived hypothetical common error. Evidence!

>   * There is a potential for confusion about the evaluation time of
>     generator parameter default value expression.

No more than anything in the body, if we use the simple and flat 
semantics Jason advocated.

I really think this evidence-free approach to overturning the generator 
design, where we've stood on Python designers' and developers' shoulders 
and prototyped for almost six years, is bad business. I know, it's "just 
es-discuss", but at this point we have consensus based on the champions 
model for ES6. What you are doing is disorderly. It would be less 
disorderly, but still objectionable, to simply cut generators (and 
default parameters).

/be


More information about the es-discuss mailing list