

Await and Defer in Coffeescript core - DanielRibeiro
https://github.com/jashkenas/coffee-script/pull/1942

======
jashkenas
For the curious -- previous discussion about adding TameJS constructs:
<https://github.com/jashkenas/coffee-script/issues/1710>

And the history of a previous attempt at doing something similar:

<https://github.com/jashkenas/coffee-script/issues/241>

<https://github.com/jashkenas/coffee-script/issues/287>

<https://github.com/jashkenas/coffee-script/issues/350>

[http://gfxmonk.net/2010/07/04/defer-taming-asynchronous-
java...](http://gfxmonk.net/2010/07/04/defer-taming-asynchronous-javascript-
with-coffeescript.html)

~~~
KeithMajhor
Dude you are awesome. I used to think splats and destructuring were what made
CoffeeScript more than just pretty Javascript. But this new stuff is doing
even more substantive work on our behalves. Thank you.

~~~
jashkenas
Thank @maxtaco -- TameJS is his baby.

------
extension
The defer syntax feels wrong to me, I think because it looks like a function
call but doesn't behave like one (because it assigns to its arguments). If it
behaves different then it should look different.

Since it creates a continuation, perhaps it should resemble the syntax for
creating a function, like this:

    
    
        await resolve "host.com", (ip, err) ~>
        console.log "#{ip} #{err}"
    

or this:

    
    
        await resolve "host.com", (ip, err) <-
        console.log "#{ip} #{err}"
        

Introducing an operator like this would also avoid some name collisions.

And does the callcc really have to be able to assign to things? Make it work
just like a formal parameter list, and then you can actually compile it into
one, avoiding all that pass-by-reference hoopla.

The autocb thing is even weirder. Magic variable names? I've never heard of a
language that resorted to this. Why not just some new syntax to mark a
parameter as the callback? Perhaps some postfix modifier, to match the splat
syntax?

    
    
        resolve = (host, callback <-) ->
          ...
          return ip, err
    

or overload a keyword?

    
    
        resolve = (host, return callback) ->
          ...
          return ip, err

~~~
DanielRibeiro
If I understood correctly, they would become keywords, like 'return', 'true',
'false' are in javascript, and 'class' is in coffeescript. The problem with it
is that any functions called _defer_ would have to be renamed in order to work
on this version of Coffeescript, possibly breaking some existing code.

~~~
tikhonj
This is really pedantic, but I also think it's important: class is a keyword
(well, really just a reserved word) in JavaScript as well. The reason it's
important is that some engines will actually have issues if you use syntax
like this[1]:

    
    
        var obj = {class : "blarg"};
    

[1]:
[https://developer.mozilla.org/en/JavaScript/Reference/Reserv...](https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words)

~~~
DanielRibeiro
Yeah, we are kinda splitting hairs here, but strictly speaking, 'class' is
reserved word in JS. It will become a keywords when they start using it. The
link you provided does make this distinction: _reserved as future keywords_.

------
ericflo
This is a game changer, in my opinion.

~~~
jnbiche
Positive or negative?

~~~
ericflo
Positive.

------
arocks
For those who didn't understand the new constructs, the following excerpt from
TameJS[1] website helps:

> `await` marks a section of code that depends on externals events, like
> network or disk activity, or a timer. An `await` block contains one or more
> calls to `defer`. Calling `defer` constructs a new deferral. Only once all
> deferrals inside an await block are fulfilled does control continue past it.
> `defer()` behaves much like a normal function; it returns an anonymous
> function that you give to your async functions. These functions "fulfill"
> their deferrals by calling the callbacks passed to them.

[1]: <http://tamejs.org/>

------
mjor
I love CoffeeScript, and I would hate to see this become part of the language
specification.

Just a few things off the top of my head:

\- Why does defer() look like any other function.

\- Completely changing the return keyword's meaning if "autocb" is a function
argument is just silly.

\- The generated JavaScript is utterly unreadable and unquestionably comes
with a performance trade-off.

------
pkulak
Is this just saving some tabs, or is it cooler than that? Will a return return
to the top function? Will exceptions get caught across callback boundaries?

------
ricardobeat
Please, no. I'll stop using coffeescript the day the compiled JS becomes
unreadable at first look. A bundled flow-control library with special syntax
privileges would be more feasible, and prevent mangling the output.

~~~
jashkenas
Don't worry -- this is currently just a pull request and a fork that you can
try out:

<http://search.npmjs.org/#/tamed-coffee-script>

The real challenge here is to see if this branch can be made to generate the
asynchronous code you would have written in the first place ... or how close
we can come to approaching it.

~~~
DanielRibeiro
I think it is a cool thing to be considered.

Mostly because you can already do it with runtime AST metaprogramming (which
is very doable in JS, due to Function.toString, even though is not as easy to
do as Lisp/Clojure's macros), and have it as lib.

What the language support adds is simply the convenience of not passing a
function with the block of code that will be instrumented. In fact, with
language support, you can even debug it.

And the best part about this change: if you don't use it, it will not affect
you at all. It is opt-in by default.

Not saying we should take this change lightly, but I believe it does have many
merits, and we should not be too quick to dismiss it.

~~~
raganwald
I’m a huge fan of stuff like this, however it’s not strictly true that
features like this are “opt in.” If you write your code alone and in a vacuum,
it’s opt-in. However, if you write your code on a team, if you use NPM
packages that were compiled from this code, if you use backbone extensions
compiled from this code, you’re opted in “by proxy” to the code it produces
whenever you find yourself stepping through the code in a debugger or reading
the compiled code in a browser environment.

IMO, it could be a win by virtue of producing _consistent_ code for the most
common cases. It may seem unfamiliar at first compared to the code you would
personally write, but if it becomes a standard and everybody’s code ends up
looking much the same, that’s a win overall.

I think this is already true for binding functions to the current ‘this’ and
for comprehensions, and we could use a standard ‘pattern’ for the resulting
asynchronous code for most common cases.

But I grant that it isn’t purely optional in a world where very few people
write their own stack in its entirety.

~~~
DanielRibeiro
Ever since I wrote this I realized that this feature, as outlined here, is not
opt-in, even in a vacuum, due to the fact that will break all variables named
'await' and 'defer'.

About using others' code: compile time code generation is always possible, and
you can't prevent the libraries you are using from using it. It can even be
worse: they can runtime code generation, or a downright obfuscator.

Since more and more languages are being compiled to JS (Clojurescript being
one formidable recent addition), trying to stay "pure" with respect to the
libraries you use is getting harder and harder.

My biggest worry is that Coffeescript starts stagnating from lack of
innovation (which seems to affect most stable languages).

One way Scala managed to experiment with features while still trying to be
stable, was through Scala Compiler Plugins[1].

This we could be having a less theoretical conversation, by throwing it in the
wild, and learning from the experiments people make with it.

[1] <http://www.scala-lang.org/node/140>

------
equark
Does this work with the Promise API without defer?

