yield and new : SpiderMonkey and the draft Spec
Dmitry Soshnikov
dmitry.soshnikov at gmail.com
Mon Mar 14 01:02:11 PDT 2011
Yep, thanks Brendan,
I filed the bug https://bugzilla.mozilla.org/show_bug.cgi?id=641436
But the thing with `this` is still interesting for me. So in this particular
case `this` should be set to `undefined`. Should it be always set to
`undefined` (strict) / global object and regardless -- calling from `new` or
via simple call? There nothing is said about `this` value of the
[[ExecutionContext]] created for the "newbord" generator. What should it be
set to?
Thanks,
Dmitry.
On Sun, Mar 13, 2011 at 11:39 PM, Brendan Eich <brendan at mozilla.com> wrote:
> Hi Dmitry,
>
> It looks to me like you've just found a bug in SpiderMonkey's generator
> implementation, which pre-dates the strawman:generators proposal by four+
> years. Please file it in the right place: https://bugzilla.mozilla.org/.
> Thanks.
>
> The bug is a regression. Here's what my Firefox 3-era JS shell does:
>
> js> // infinite objects generator
> js> let g = new function () {
> this.x = 10;
> while (true) {
> yield;
> }
> };
> js>
> js> // generate an array of 3 objects
> js> let objects = [1, 2, 3].map(function(i) g.next());
> js> objects
> ,,
> js> uneval(objects)
> [(void 0), (void 0), (void 0)]
>
> Clearly, yield; should not yield a mysterious object as the return value of
> g.next().
>
> /be
>
> On Mar 13, 2011, at 3:04 PM, Dmitry A. Soshnikov wrote:
>
> 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 at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110314/6a45fca2/attachment-0001.html>
More information about the es-discuss
mailing list