archives

« Bugzilla Issues Index

#3626 — 14.4.12 EvaluateBody: Allow "new function*" to reference `this`


14.4.12 Runtime Semantics: EvaluateBody

Add BindThisValue when a generator function is new'ed, so the following example works again.

---
function* g() { print(this) }
var it = new g();
it.next();
---


The note in 14.4.12 says:
NOTE If the generator was invoked using [[Call]], the this binding will have already been initialized in the normal manner. If the generator was invoked using [[Construct]], the this bind is not initialized and any references to this within the FunctionBody will produce a ReferenceError exception.


There are two reasons for this behavior:

1) generator methods need 'this' to refer to the object the method was invoked upon, not the resulting generator instance. for example:

class Foo {
*ownName() {
yield* Object.getOwnPropertyNames(this);
}
}

It would be confusing if generator methods bound 'this' one way and generator function declarations did something difference.

2) Within the body of a generator function (or anything called from the generator body you can't do anything interesting with the generator object the body is operating upon. In particular, invoking 'next', 'return', or 'throw' on the active generator from within the body throws (see 25.3.3.2) and those are really the only useful things you can do with a generator object. Making 'this' be a reference to the active generator object would just be an invitation to try to do things that can't be done.

Finally, if you really want to print or otherwise get access to the active generator object, it's easy enough to accomplish:

function; g() {
let thisGenerator = function*() { print(thisGenerator) }();
return thisGenerator
}


(In reply to Allen Wirfs-Brock from comment #1)
> There are two reasons for this behavior:
>
> 1) generator methods need 'this' to refer to the object the method was
> invoked upon, not the resulting generator instance. for example:
>
> [...]
>
> It would be confusing if generator methods bound 'this' one way and
> generator function declarations did something difference.
>

Accessing `this` in new'ed generator methods and generator function declarations currently results in a ReferenceError. So I don't understand what you mean be "did something different".


> 2) Within the body of a generator function (or anything called from the
> generator body you can't do anything interesting with the generator object
> the body is operating upon. In particular, invoking 'next', 'return', or
> 'throw' on the active generator from within the body throws (see 25.3.3.2)
> and those are really the only useful things you can do with a generator
> object. Making 'this' be a reference to the active generator object would
> just be an invitation to try to do things that can't be done.
>
> Finally, if you really want to print or otherwise get access to the active
> generator object, it's easy enough to accomplish:
>
> function; g() {
> let thisGenerator = function*() { print(thisGenerator) }();
> return thisGenerator
> }

FWIW, this use case was once mentioned in [1]. If `this` stays to be non-functional in new'ed generator functions, I'd almost like to propose to forbid `new` on generators. But then we're back to bug 1489 which I don't want to re-open right now.

[1] https://esdiscuss.org/topic/retrieving-generator-references


(In reply to André Bargull from comment #2)
> (In reply to Allen Wirfs-Brock from comment #1)

> >
> > It would be confusing if generator methods bound 'this' one way and
> > generator function declarations did something difference.
> >
>
> Accessing `this` in new'ed generator methods and generator function
> declarations currently results in a ReferenceError. So I don't understand
> what you mean be "did something different".

I meant have different non-error behavior.

>
> ...

> FWIW, this use case was once mentioned in [1]. If `this` stays to be
> non-functional in new'ed generator functions, I'd almost like to propose to
> forbid `new` on generators. But then we're back to bug 1489 which I don't
> want to re-open right now.

I agree, on both points.

I think meta properties may be a solution to some of the issues that have been raised:

function.startValue value passed into a generator by first nest
function.generator the current generator object instance