Await and Defer in Coffeescript core
github.com
github.com
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...
A post that stands on its own, whether you like/care about Coffeescript/Javascript or not.
[1] http://gfxmonk.net/2010/07/04/defer-taming-asynchronous-java...
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 var obj = {class : "blarg"};
[1]: https://developer.mozilla.org/en/JavaScript/Reference/Reserv...> `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/
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.
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.
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.
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.
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.
async.knead flour, water, (err, dough) ~>
return log err if err?
async.bake dough, (bread) ~>
eat bread
BTW, was looking back at the original announcement here at HN, and found this: CoffeeScript + node.js + V8 could produce one amazing
language and implementation.
Little did he know... http://news.ycombinator.com/item?id=1014080You maintain a two-way mapping between file names/line numbers in the CS source and file names/line numbers in the JS source. When the debugger throws an exception with a line number, just translate it before presenting it to the user. For break points and stepping, go in the opposite direction.