Allen Wirfs-Brock wrote:
There would be another way to accomplish supporting generator return values that doesn't
require dynamically constructing new StopIteration instances and avoids all Realm issues:
Capture the return value in the generator instance when it enters the "closed"
state and then throw the single immutable StopIteration object (could be a Symbol). A
client of the generator instance that catches StopIteration and expects a return value
can directly query the generator instance (via a property access) to get that return
value. It accomplishes the same thing but doesn't require multiple StopIteration
instances, an extract allocation on generator returns, a call to isStopIteration to test,
etc.
This is not the PEP-380 path we've championed, but let's talk about it.
Say the generator-iterator has a .value property that contains the
return value. Any for-of iteration will suppress the value, so no
difference there. A task.js (http://taskjs.org) style scheduler, on the
other hand, will have to do something like this (diff from
ES6-as-proposed task.js indicated with -/+ lines):
function runScheduledTask(task) {
var result = task.result, send = (task.runState === R_RESOLVED);
try {
task.runState = R_RUNNING;
task.result = void 0;
if (task.threadState === T_CANCELLED) {
task.thread.close();
task.result = void 0;
task.runState = R_RESOLVED;
task.threadState = T_CLOSED;
} else {
var p = (send ? task.thread.send(result) :
task.thread["throw"](result)) || READY;
task.runState = R_BLOCKED;
p.then(function(value) {
task.result = value;
task.runState = R_RESOLVED;
if (task.threadState === T_STARTED) {
task.scheduler.schedule(task);
pump(task.scheduler);
}
}, function(e) {
task.result = e;
task.runState = R_REJECTED;
if (task.threadState === T_STARTED) {
task.scheduler.schedule(task);
pump(task.scheduler);
}
});
}
} catch (e) {
task.threadState = T_CLOSED;
if (e instanceof StopIteration) {
- task.result = e.value;
+ task.result = task.thread.value;
task.runState = R_RESOLVED;
task.deferred.resolve(e.value);
} else {
task.result = e;
task.runState = R_REJECTED;
task.deferred.reject(e);
}
}
}
Not much of a change, but something crucial is lost. The try could
possibly .send or .next another task's generator-iterator (task.thread),
possibly under pump if it immediately dispatched (it doesn't, but
suppose it did). You're programming by side effects here, requiring the
catcher of e to know that task.thread.value is the mutable pigeon-hole
to inspect.
This smells pretty bad compared to the PEP-380 style alternative, which
cleanly localizes the result to e.value.
/be
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss