yield and new : SpiderMonkey and the draft Spec

John J. Barton johnjbarton at johnjbarton.com
Mon Mar 14 21:50:45 PDT 2011

On 11:59 AM, Brendan Eich wrote:
> However, there's no way for a generator function to return that instance, because a generator function always implicitly returns a fresh generator iterator when invoked. It could store |this| in the heap, and whatever value |this| receives is saved as part of the shallow continuation capture by the generator.
The implicit return of a fresh generator iterator makes the example 
confusing. It also makes simple examples difficult. For example from

function simpleGenerator(){
   yield "first";
   yield "second";
   yield "third";
   for (var i = 0; i<  3; i++)
     yield i;

var g = simpleGenerator();
print(g.next()); // prints "first"

The developer has to read the code for simpleGenerator and scan an 
arbitrary number of lines for 'yield' to realize that the statement
    var g = simpleGenerator();
is an implicit constructor of a special object and only when g.next() is 
run will any statement from simpleGenerator-the-real-function-we-wrote 
be called.  A debugger stopped on the line that creates |g| will want to 
step-into simpleGenerator(); if it does the result is puzzling, it has 
to step back immediately; if does not step-into simpleGenerator() the 
result is puzzling, why did the debugger fail? So we are stuck with some 
warning-message special-case solution, "oh this function is a generator!".

Suppose we had a built-in function Generator:
    var g = new Generator(simpleGenerator);
Now I read once the documentation for Generator. I see it takes a 
function argument which must contain the keyword 'yield' and it creates 
a special object with two methods, next() and send().  I never need to 
read the body of simpleGenerator. (Generator.create(simpleGenerator) 
would also work).

Furthermore if I stop a debugger at the line above and single step into, 
it would be perfectly reasonable for the debugger to simply step to the 
next line and show |g| is now a Generator object.  That's how built-in 
things work, it's ok.

Now consider Dmitry's example:

// infinite objects generator
>>  let g = new function () {
>>    this.x = 10;
>>    while (true) {
>>      yield;
>>    }
>>  };

It becomes:
// infinite objects generator
let g = new new Generator (function () {
    this.x = 10;
    while (true) {

Brendan's explanation of this case is now not necessary: by making the 
implicit constructor explicit we see immediately that the |new| is not 
doing what one expected from Dmitry's original code.


More information about the es-discuss mailing list