yield and new : SpiderMonkey and the draft Spec

Dmitry A. Soshnikov dmitry.soshnikov at gmail.com
Sun Mar 13 13:04:55 PDT 2011


Hello,

I hope you can help with explaining of what is going on with `this` 
value inside the body of a generator?

Consider e.g. the following case:

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

// generate an array of 3 objects
let objects = [1, 2, 3].map(function(i) g.next());

console.dir(objects);

Results:

[
     [[Class]]: "Array",
     length: 3,
     0: {
         [[Class]]: "Object",
         x: 10
     },
     1: {
         [[Class]]: "Object"
     },
     2: {
         [[Class]]: "Object"
     }
]

Only first object has `x` property. Also:

console.log(objects[0] == objects[1]); // false
console.log(objects[1] == objects[2]); // false



As I understand, [[Construct]] activated by the `new` calls [[Call]] of 
the function, which produces the `g` generator. I look here: 
http://wiki.ecmascript.org/doku.php?id=strawman:generators and see:


    Calling

Let |f| be a generator function. The semantics of a function call |f(x1, 
..., xn)| is:

Let E = a new VariableEnvironment record with mappings for |x1| ... |xn|
Let S = the current scope chain extended with E
Let V = a new generator object with
[[Scope]] = S
[[Code]] = f.[[Code]]
[[ExecutionContext]] = *null*
[[State]] = "newborn"
[[Handler]] = the standard generator handler
Return V


So, `g` will be the generator with the needed [[Code]] and empty 
[[ExecutionContext]]. Notice, there nothing is said about `this` value.

In calling `next` (i.e. `send(undefined)`) we get into:


    Internal method: send

G.[[Send]]

Let State = G.[[State]]
If State = "executing" Throw Error
If State = "closed" Throw Error
Let X be the first argument
If State = "newborn"
If X != *undefined* Throw TypeError
Let K = a new execution context as for a function call
K.currentGenerator := G
K.scopeChain := G.[[Scope]]
Push K onto the stack
Return /Execute/(G.[[Code]])
G.[[State]] := "executing"
Let Result = /Resume/(G.[[ExecutionContext]], *normal*, X)
Return Result

We see that a new context is created but again, nothing is said about 
its `this` value.

When evaluating /Execute/(G.[[Code]]) we with yield get into:


    Yielding

The semantics of evaluating an expression of the form |yield e| is:

Let V ?= Evaluate(e)
Let K = the current execution context
Let O = K.currentGenerator
O.[[ExecutionContext]] := K
O.[[State]] := "suspended"
Pop the current execution context
Return (*normal*, V, *null*)


Btw, what does "?=" mean?

Here the K is the context created on in the `send` method (still we 
haven't any info about `this` value).

The following call to `next` will again enter `send` method with 
`undefined` but we already get into:


    Resuming generators

*Operation* /Resume/(K, completionType, V)

Push K onto the execution context stack
Let G = K.currentGenerator
Set the current scope chain to G.[[Scope]]
Continue executing K as if its last expression produced (completionType, 
V, *null*)

where we proceed with evaluating previously saved continuation. And 
again, nothing about `this` is said.

As I see, during all these steps always the same K is passed around and 
evaluated. `This` value is a property of the context and K has it, but 
which?

As was shown in the example above, `this` is set to the newly created 
object, but it's a current SpiderMonkey's behavior; don't know how it 
correlate with this draft spec.

Consider e.g. the following example (tested in SpiderMonkey):

g = new function() {
   yield new Boolean((yield) == this)
};

console.log(''+ g.send(g.next())); // false

g = new function() {
   yield new Boolean(this == (yield))
};

console.log(''+ g.send(g.next())); // true

Why in first call `yield` wasn't newly created object and in the second 
one -- it was? What actually _should_ yield without an argument yields? 
`undefined` I guess.

So don't know which behavior is correct and whether it's a strange 
behavior in current SpiderMonkey.

Thanks,
Dmitry.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110313/aae7d4a1/attachment.html>


More information about the es-discuss mailing list