creationix/gen-run — pull request #7 by TomiBelan (2013-08-31 08:19:08+00:00)
Title: Always use an implicit done callback

This pull request is branched off from #6. You probably want to look at 52b86fd0b153168f63919426572e14b051039141, not the combined diff of both this and #6. If you want to merge it without #6, tell me and I'll rebase it.

What the code does:
Remove nextPlain() and always use nextSafe(). If the user hasn't provided a done callback, use an implicit one that throws exceptions globally in a new call stack.

***

Tl;dr why:
```js
var run = require('./.');

function fragileAsyncOperation(number, cb) {
console.log("doing setup");
process.nextTick(function () {
cb(null, number * number);
console.log("doing cleanup"); // I sure hope this gets executed!
});
}

function *myProgram(gen) {
console.log("program start");
yield process.nextTick(gen());
yield fragileAsyncOperation(8, gen());
null(); // a wild type error appeared!
}

run(myProgram, function(e){ console.log(e); }); // runs cleanup :)
setTimeout(function() { run(myProgram); }, 1000); // doesn't run cleanup :(
// (the setTimeout is there to distinguish which run is which)
```

***

Looong and detailed why:

Async functions have _invariants_ -- rules that everyone must follow. The main rule is something like this: "If I call an async function and give it a callback, that async function will never throw anything, and it will make sure the callback gets called exactly once." I hope you'll agree that this rule is correct and useful. A lot of code implicitly assumes the rule holds. If an async function throws, or calls the callback twice, or not at all, everything breaks. (Of course, not everyone follows the rule -- that's why gen-run has protection against double calls etc. But ideally everyone would.)

To make the main rule work, you also need other rules, such as: "The callback must never throw anything either." Because what if the async function is actually synchronous:
```js
function myAsyncFunction(..., cb) {
cb(null, ...);
}
```
Or what if it uses some error handling like this one:
```js
function myAsyncFunction(..., cb) {
doSomethingAsynchronous(..., function (...) {
try {
var result = ...; // might throw
cb(null, result);
} catch (e) {
cb(e); // oh dear -- if cb throws, we might call it twice!
}
});
}
```
Or what if the async function wants to do some cleanup after calling cb, like the example above. (Though that might be less common.)

When you call an async function and give it a callback you're actually promising to the async function that the callback is well-behaved and won't do something unexpected like throwing exceptions.

In our case, the async function is `n.value` and the callback we're giving it is `gen()`. So the rule says `gen()` should never throw, which means `check` should never throw, which means `next` should never throw. Which means if you ever use `nextPlain`, you break the main async rule. So this PR removes it and just uses `nextSafe` all the time.

But then, what to do when the generator actually throws an exception? We need to catch it because throwing something from `gen()` is not allowed by the rule, but we don't want to silently swallow it. Lacking a better option, we throw the exception globally, in a new call stack created by `setTimeout(..., 0)`. We could've also used `process.nextTick`, but `setTimeout` also works in browsers and the distinction isn't very important in this case. (Btw, [streamline.js does this too](https://github.com/Sage/streamlinejs/blob/master/lib/callbacks/runtime.js#L117).)

This whole matter is quite complex, so if you're not convinced, let's discuss further.