A syntax alternative for generators (was: Generator issue: exceptions while initializing arguments)

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Sep 11 09:40:43 PDT 2012


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.  What follow is an attempt to sketch the thought process that lead to that conclusion:


On Sep 9, 2012, at 11:32 PM, Brendan Eich wrote:

> 
> function dataSnapshot(aCollection) {
>  let snapshot = aCollection.clone();
>  return function*() {
>    for (let i = 0; i < snapshot.length; i++){
>      yield snapshot[i];
>    }
>  }();
> }
> 


Issues:
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.
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
               }
         }();
    }
}

Generator function definitions need to be called to create an actual iterator object (a generator instance)
It is likely that a common error will be forgetting the invocation of the generator in return statements such as the above.
There is a potential for confusion about the evaluation time of generator parameter default value expression. If a parameterized generator needs default value initialization it is probably  better practice to accomplish that via a wrapper factory: 
function IteratorCol(col =  CollectionManager.default()) {
   return function*() {for (let i = 0; i < col.length; i++) yield col[i]}();
}

is argubaly clearer and more likely to be correct than

function *IteratorCol(col =  CollectionManager.default()) {
   for (let i = 0; i < col.length; i++) yield col[i];
}
But the wrapper form is less concise  than the unwrappered form. 
Concise method declarations for generators are misleading about the interface of the containing class/object because they place emphasis on an implementation detail (use of a generator to provide an Iterator implementation) rather than the more important fact that the method returns a object that can be used as an iterator.

A different approach:
eliminate formal parameters from generator definitions -- if arguments are needed use a wrapper function/method
eliminate the need to call a generator before before using it as an iterator.  Generator definitions create generator instances rather than generator constructor functions.
use lexical this/super binding within generator definitions
base generator definition syntax off of arrow function syntax rather than function definition syntax
eliminate concise generator methods

Examples:

function dataSnapshot(aCollection) {
 let snapshot = aCollection.clone();
 return *=>{
   for (let i = 0; i < snapshot.length; i++){
     yield snapshot[i];
   }
 };
}

or more concisely:

function dataSnapshot(aCollection) {
 let snapshot = aCollection.clone();
 return *=>for (let i = 0; i < snapshot.length; i++) yield snapshot[i];
}

as a method:

class MyClass {
   dataSnapshot(aCollection = CollectionManager.default()) {
        let snapshot = aCollection.clone();
        return *=>for (let i = 0; i < this.length; i++) yield this[i];
    }
}



Proposal summary:
Generator literals -- Base generators syntax on arrow functions rather than function declarations/expressions
lexical this/super
expression or curly body
Generator literals don't have formal parameters 
Generators aren't called -- generator literals create generator instances (a kind of iterator) when evaluated
No concise generator methods -- use a concise method returning a generator literal 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120911/99229971/attachment.html>


More information about the es-discuss mailing list