I'm new both to Dart and to asynchronous programming, so this is just my very humble opinion.
Your Circuits looks interesting, but I don't think they're a big improvement over raw futures. For instance, let's look at a couple of examples taken from your documentation.
Here's the first one:
Future<int> add(a, b) => new Future(() => a + b);
Future<int> add4(a, b, c, d) {
return new Circuit([
(@out sum1) => sum1 << add(a, b),
(@out sum2) => sum2 << add(c, d),
(sum1, sum2, @out result) => result << add(sum1, sum2)
]);
}
And here's how I'd do that without circuits:
Future<int> add(a, b) => new Future(() => a + b);
Future<int> add4(a, b, c, d) {
var sum1 = add(a, b);
var sum2 = add(c, d);
return Future_call(add, sum1, sum2);
}
Here I use a function called Future_call which waits for both sum1 and sum2 to complete and then passes the values to add. I'm not sure such a function can be implemented efficiently in Dart. I've just read that Dart doesn't support varargs, etc... IMHO that's a big limitation because it makes difficult to write functions that modify other functions.
Here's the second example:
sumProgression(n) {
int acc=0, k=1;
return new Circuit([
(@out s) { s << add(acc, k++); },
(s, @out next, @out result) { acc=s; (k <= n ? next : result) << acc;}
]);
}
which isn't as intuitive as you think. I prefer my version without circuits:
sumProgression(n) {
if (n <= 0) return new Future.value(0);
else return sumProgression(n - 1).then((sum) => add(sum, n));
}
The only drawback is that n can't be too big. More efficient:
sumProgression(n) {
recur(acc, i) {
if (i > n) return acc;
else return new Future(() => recur(Future_call(add, acc, i), i + 1));
}
return recur(new Future.value(0), 1);
}