Reason why generators do not have references to themselves?

Allen Wirfs-Brock allen at wirfs-brock.com
Thu Jan 23 16:54:20 PST 2014


On Jan 23, 2014, at 2:14 PM, Bradley Meck wrote:

> I was playing around with generators / looking at await for promises and notices a very difficult thing revolving around generators not having a reference to themselves.
> 
> See: 
> 
> https://gist.github.com/bmeck/72a0f4f448f20cf00f8c
> 
> I have to end up wrapping the generator function to get a reference to the generator for passing to nested functions.
> 
> Is there a reason the execution context is not a generator / there is no reference back to the generator during [[call]]?

The [[Call]] whose execution context is suspended and captured is by the generator instance is the actual call to the generator function that created that instance.  So, the this value of that context is the this value of that original call of the generator function. Creation and initialization of the generator instance takes place before executing the generator function body. This means there are some interesting ways that the this value manifests depend upon the nature of the this call. 

For example,
(this is what the ES6 spec. says should happen, I don't know if any implementation has this all correct yet)

Assume:
 
function g* () {"use strict"; yield "this: " + this};  //don't want undefined this turning into the global object

g.prototype = function toString() {return "a generator instances made by g"};
var obj = {
     g,
     toString() {return "obj"}
};

//plan function call
console.log(g().next().value);  //"this: undefined" 
//same as 
console.log(g.call(undefined).next().value);  
//Just like calling any function call, undefined is the default this value.

//method call
console.log(obj.g().next().value); //"this: obj"
//same as:
console.log(g.call(obj).next().value);  
//just like any method call

//explicit constructor call
console.log((new g()).next().value): //"this: a generator instances made by g"
//same as:
console.log(g.call(g[Symbol.create]()).next().value);  
//just like newing any constructor function

In other words, if you want this bound to the function instance within the body of the constructor function use the generator function as a constructor and new it. 

How, does it all work?  It depends upon the generator function being to distinguish an uninitialized generator instance from other objects.  This is something that all constructors that want to have the same behavior for both new and regular calls need to be able to do.

The prolog of a generator function (before capturing and suspending the execution context) looks at the this value that was passed to it.  If the this value is an uninitialized generator object (such as is returned by the @@create method of a generator function) it initializes that generator object, captures the execution context, and return the now initialized generator object that was passed in as its this. 

If the this value is anything else (undefined, any object that isn't an uninitialized generator instance) the prolog allocates a new generator instance (using @@create), initializes it, captures the context and returns the newly allocated  generator instance. 

In neither case is the original this binding modified.

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


More information about the es-discuss mailing list