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.
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to