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

Reply via email to