jashkenas/coffeescript — pull request #3731 by epidemian (2014-11-19 06:05:36+00:00)
Title: Implement void operator

While this PR might seem like an uncalled attempt of bringing [a weird operator from JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void) nobody seems to miss back to CoffeeScript, it's *actually* a little stab at trying to solve #2477, i.e., "Remove implicit returns?".

But without removing implicit returns :smiley_cat:

### tl;dr

`void` allows fixing the problems [cited by @Zyphrax](https://github.com/jashkenas/coffeescript/issues/2477#issuecomment-61563076) in an arguably more elegant way than adding `return`s everywhere. For example, [this tricky jQuery event handler problem](http://jsfiddle.net/63fUY/) ([source](https://news.ycombinator.com/item?id=5389245)) can be fixed by "voiding" the last boolean assignment:

```coffeescript
# Toggle when the toggle button is clicked
nextState = off
$('#btn').click ->
$('#state').text if nextState then "On" else "Off"
void nextState = !nextState
```

↓

```javascript
var nextState;

nextState = false;

$('#btn').click(function() {
$('#state').text(nextState ? "On" : "Off");
nextState = !nextState;
});
```

Or, if you want to avoid [creating a big array](http://programmaticallyspeaking.com/why-i-hate-implicit-return-in-coffeescript.html) because the last expression of your function is a `for` comprehension, `void` can save you there too!

```coffeescript
x = (n) ->
void for i in [0...n]
dostuff i
```

↓

```javascript
var x;

x = function(n) {
var i, _i;
for (i = _i = 0; 0 <= n ? _i < n : _i > n; i = 0 <= n ? ++_i : --_i) {
dostuff(i);
}
};
```

This way, `void` retains basically the same meaning from JS: it evaluates the expression we pass it and returns `undefined`, with the added benefit of the compiler being able to avoid generating a `return` statement if `void` is the last expression of a block because it knows about its semantics.

### But why not a different function symbol?

I actually [was in favour](https://github.com/jashkenas/coffeescript/pull/2726#issuecomment-14139799) of using `!->` or `-/>` to denote procedures. But it has quite a nasty problem: the combinatorial complexity of having various "modifier" behaviours for functions. Now we have only one modifier, whether the function is "bound" or not, so we have two symbols: `->` and `=>`. Adding an extra modifier, whether it returns useful values or not, would require having *four* symbols: `->`, `=>`, `!->` and `!=>`. Now image if we decided to implement generators as yet another modification of the function syntax... yes, *eight*(!!!) symbols: `->`, `=>`, `!->`, `!=>`, `->*`, `=>*`, `!->*` and `!=>*`.

It's not only about the grammar complexity, but mostly about the cognitive load of having to pick between many different function types whenever you want to write a damn function. Right now the picking is pretty easy: always pick `->`, and if later on i discover that i need the `this` of the parent context, change it to `=>`. Done. And it should stay that simple :wink:

### So, why `void` then?

I don't know, it just occurred to me when considering alternative solutions for the sour #2477 issue. At first i thought it was a stupid idea, but after giving it a try it started to make some sense.

First, i think it fits Coffee's philosophy of "everything is an expression" quite nicely. `void ` is itself just an expression, that just happens to always be `undefined`.

Also, i think that Coffee/Ruby programmers develop a habit of looking at the bottom of blocks to see what they evaluate to. Ideas like the `!->` function syntax or [specifying the return value before the function body](https://github.com/jashkenas/coffeescript/issues/3583) break that expectation, while `void` doesn't.

The fact that `void` concept is independent of the "function type" is also a big win. It avoids the possible combinatorial explosion of complexity mentioned above.

And it's also worth noting that `void` is already a part of JavaScript; it's not a new concept. It's even a reserved keyword on today's CoffeeScript, so it's not like this change could break code that uses `void` as an identifier.

### Sooo... should i then start using void at the end of most of my functions?

Simply put: no! I mean, you can. But it's not in the spirit of this proposal to have `void` as something one would use in the general case of writing procedural functions.

For example, it doesn't make sense to have all your test case functions end on `void` because you don't care about the return value. If you don't care, just leave the last expression be returned, and trust that the testing framework won't care about that return value either.

`void` should be used sparingly, to mark cases where it *is* important that the function returns undefined:

```coffeescript
secretLocked = yes
$('#hidden-secret-unlocker').click -> void secretLocked = no # We don't want the click event to stop bubbling up.
```

----

Well, that's all, i hope this proposal can bring an adequate solution for people having trouble with implicit returns, while at the same time not make the language much uglier for people not having problems with them.

What do you people think? :smiley_cat: