On Sep 6, 2011, at 10:10 AM, Dean Landolt wrote:
> On Tue, Sep 6, 2011 at 12:37 PM, John J Barton <johnjbar...@johnjbarton.com>
> wrote:
>
> I was more thinking along the lines of better support for async programming
> that does not attempt to look sync (I have no idea what that means).
>
>
> I'm also curious what "better support for async programming" looks like --
> that always seem to boil down to a `wait` construct -- which it's already
> been established is not enabled by harmony generators.
Hi Dean, I hope you don't mind if I quibble here: generators do enable (as in
make possible, but not fully implement) async or deferred functions. You need a
scheduler and an event loop concurrency model in addition to generators for the
full monte, but generators are co-expressive with the control-effect part of
async or deferred functions.
Here is Dave Herman's desugaring write-up:
======================================================================
Library for creating intrinsic deferred objects
-----------------------------------------------
function IntrinsicDeferred(generator) {
this.state = "newborn";
this.generator = generator;
this.callbacks = [];
this.errbacks = [];
this.completion = null;
this.continue(void 0, true);
}
IntrinsicDeferred.prototype = {
continue: function(value, normal) {
if (this.state === "running" || this.state === "finished")
throw new Error("illegal state");
this.state = "running";
let received;
try {
received = normal ? this.generator.send(value)
: this.generator.throw(value);
} catch (e) {
if (isStopIteration(e))
this.callback(e.value);
else
this.errback(e);
return;
}
let { awaited, callback, errback } = received;
awaited.then(callback, errback);
return;
},
then: function(cb, eb) {
if (this.state === "finished") {
if (this.completion.type === "return" && cb)
cb(this.completion.value);
if (this.completion.type === "error" && eb)
eb(this.completion.value);
return;
}
if (cb)
this.callbacks.push(cb);
if (eb)
this.errbacks.push(eb);
},
createCallback: function(used) {
let D = this;
return function(value) {
if (used.value)
throw new Error("cannot reuse continuation");
used.value = true;
D.continue(value, true);
};
},
createErrback: function(used) {
let D = this;
return function(value) {
if (used.value)
throw new Error("cannot reuse continuation");
used.value = true;
D.continue(value, false);
};
},
await: function(awaited) {
this.state = "suspended";
let used = { value: false };
return {
awaited: awaited,
callback: this.createCallback(used),
errback: this.createErrback(used)
};
},
cancel: function(value) {
if (this.state === "running" || this.state === "finished")
throw new Error("illegal state");
this.state = "running";
try {
this.generator.close();
} finally {
this.errback(value);
}
},
callback: function(value) {
this.state = "finished";
this.completion = { type: "return", value: value };
let a = this.callbacks, n = a.length;
for (let i = 0; i < n; i++) {
try {
let cb = a[i];
cb(value);
} catch (ignored) { }
}
this.callbacks = this.errbacks = null;
},
errback: function(value) {
this.state = "finished";
this.completion = { type: "error", value: value };
let a = this.errbacks, n = a.length;
for (let i = 0; i < n; i++) {
try {
let eb = a[i];
eb(value);
} catch (ignored) { }
}
this.callbacks = this.errbacks = null;
}
};
Translation of deferred function <D>:
-------------------------------------
deferred function <name>(<params>) { <body> }
~~>
function <name>(<params>) {
let <D> = new IntrinsicDeferred((function* <name>() { <body> }).call(this,
arguments));
return {
then: <D>.then.bind(<D>),
cancel: <D>.cancel.bind(<D>)
};
}
Translation of await expression within deferred function <D>:
-------------------------------------------------------------
await <expr>
~~>
yield <D>.await(<expr>)
Translation of return statement within deferred function <D>:
-------------------------------------------------------------
return <expr>;
~~>
return <expr>;
return;
~~>
return;
======================================================================
Note how the ability to return <expr>; from a generator, the PEP 380 extension
written up for harmony:generators, is used by the next-to-last translation rule.
> So AFAICT they do exactly what you're asking -- provide language level
> support for libraries to take async control flow in new directions, all
> without shared state, spooky action at a distance, or attempting to "look
> sync" :)
Right!
John: I know of no way to make async code "look sync" without raising the risk
of code writers and reviewers missing the preemption points, resulting in lost
invariants (data races). This is the main objection to deep continuations that
I gave. Explicit syntax -- yield, await, wait, etc. -- is best. What people
most object to in function nests are the rightward indentation and the closure
entrainment (leak/bloat) hazard.
Generators and libraries built on them avoid rightward drift and nested
closures. I demo'd an example at NodeConf in May -- see
http://brendaneich.com/2011/05/mozillas-nodeconf-presentation/.
/be
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss