jashkenas/coffee-script — pull request #2729 by mintplant (2013-02-27 00:27:39+00:00)
Title: Add postfix return statements

There are a bunch of different ways to tunnel errors through asynchronous functions.

```coffeescript
# You could use an if clause and indent your code.
# This is ugly, and inflates your indentation level.
processFile = (file, cb) ->
fs.readFile file, 'utf8', (err, data) ->
if err?
cb err
else
cb undefined, doSomething(data)

# You could add a return statement to the end of your if clause.
# This can be hard to read, and still isn't a one-liner.
processFile = (file, cb) ->
fs.readFile file, 'utf8', (err, data) ->
if err?
cb err
return

cb undefined, doSomething(data)

# Or, you could return the call to the callback.
# This, though, leaks the callback return value,
# and is kind of an abuse.
processFile = (file, cb) ->
fs.readFile file, 'utf8', (err, data) ->
return cb(err) if err?
cb undefined, doSomething(data)

# You could use parentheses to combine the callback call
# and return statement.
# This requires the usage of semi-colons.
processFile = (file, cb) ->
fs.readFile file, 'utf8', (err, data) ->
(cb err; return) if err?
cb undefined, doSomething(data)
```

________

I propose adding a postfix return statement - that is, adding `and return` to the end of an expression would execute the expression and then return nothing.

So, this:

```coffeescript
processFile = (file, cb) ->
fs.readFile file, 'utf8', (err, data) ->
cb err and return if err?
cb undefined, doSomething(data)
```

Would compile to this:

```javascript
(function() {
var processFile;

processFile = function(file, cb) {
return fs.readFile(file, 'utf8', function(err, data) {
if (err != null) {
cb(err);
return;
}
return cb(void 0, doSomething(data));
});
};

}).call(this);
```

A more complex example:

```coffeescript
readFiles = (directory, cb) ->
fs.readdir directory, (err, files) ->
cb err and return if err?
output = {}
for file in files then do (file) ->
fs.readFile path.join(directory, file), 'utf8', (err, data) ->
cb err and return if err?
output[file] = data
files.pop()
cb undefined, output if files.length is 0
```

______

In the attached implementation, `and return`, appended to a statement, is rewritten to a `POST_RETURN` token (the rewriter watches for a `LOGIC/&&` token followed by a `RETURN/return` token). This then triggers a special case on the `Return` node.

______

Thoughts?