Awesome
Generator function.sent Meta Property
Status
<dl> <dt>Stage: <dd>2 <dt>Author: <dd>Allen Wirfs-Brock (May 13, 2015) <dt>Champion: <dd>HE Shi-Jun (@hax) </dl>The Problem
When the next
method is invoked on a generator objects, the value passed as the first argument to next
is "sent" to the generator object and becomes available within the body of the generator function as the value of the yield
expression that most recently suspended the generator function. This supports two-way communications between the a generator object and its consumer.
However, the first next
that a generator's consumer invokes to start a generator object does not correspond to any yield
within the body of the generator function. Instead, the first next
simply causes execution of the generator function body to begin at the top of the body.
Because there the first next
call does not correspond to a yield
within the generator function body there is currently no way for the code with the body to access the initial next
argument. For example:
function *adder(total=0) {
let increment=1;
while (true) {
switch (request = yield total += increment) {
case undefined: break;
case "done": return total;
default: increment = Number(request);
}
}
}
let tally = adder();
tally.next(0.1); // argument will be ignored
tally.next(0.1);
tally.next(0.1);
let last=tally.next("done");
console.log(last.value); //1.2 instead of 0.3
In the above example, the argument to the next
method normally supplies the value to added to a running tally. Except that the increment value supplied to the first next is ignored.
This proposal provides an alternative way to access the next
parameter that works on the first and all subsequent invocations of a generator's next
method.
The Proposal
A new meta-property: function.sent
Value and Context
The value of function.sent
within the body of a Generator Function is the value passed to the generator by the next
method that most recently resumed execution of the generator. In particular, referencing function.sent
prior to the first evaluation of a yield
operator returns the argument value passed by the next
call that started evaluation of the GeneratorBody.
function.sent
can appear anywhere a YieldExpress would be legal. Referencing function.sent
outside of a GeneratorBody is a Syntax Error.
Usage Example
Here is how the above example might be rewritten using function.sent
function *adder(total=0) {
let increment=1;
do {
switch (request = function.sent){
case undefined: break;
case "done": return total;
default: increment = Number(request);
}
yield total += increment;
} while (true)
}
let tally = adder();
tally.next(0.1); // argument no longer ignored
tally.next(0.1);
tally.next(0.1);
let last=tally.next("done");
console.log(last.value); //0.3
Specification Updates
The following are deltas to the ECMAScript 2015 Language Specification
8.3 Execution Contests
The following row is added to Table 24:<br>
Component | Description |
---|---|
LastYieldValue | The value of the most recently evaluated YieldExpression |
12.3 Left-Hand-Side Expression
Syntax
MemberExpression<sub>[Yield]</sub> : <br> ... <br> MetaProperty<sub>[?Yield]</sub> <br> ...
MetaProperty<sub>[Yield]</sub> : <br> NewTarget <br> [+Yield] FunctionSent
14.4 Generator Function Definitions
Syntax
FunctionSent : <br> function . sent
14.4.14 Evaluation
FunctionSent : function . sent<br> 1. Assert: the running execution context is a Generator Context.<br> 2. Let genContext be the running execution context.<br> 3. Return the value of the LastYieldValue component of genContext .<br>
25.3.3.1 GeneratorStart(generator, generatorBody)
Between lines 3 and 4 of the ES6 algorithm add the following step:
3.5. Set the LastYieldValue component of genContext to undefined.
25.3.3.3 GeneratorResume(generator, value)
Between lines 8 and 9 of the ES6 algorithm add the following step:
8.5. Set the LastYieldValue component of genContext to value.
25.3.3.5 GeneratorYield(iterNextObj)
Between lines 5 and 6 of the ES6 algorithm add the following step:
5.5. Set the LastYieldValue component of genContext to undefined.