

IcedCoffeeScript - swannodette
http://maxtaco.github.com/coffee-script/

======
swannodette
This fork brings some up deep issues, perhaps intractable, around about the
development of syntax-y languages. Useful source transformations require
marginalized forks of the compiler and all the development burden and risks
that entails. In some sense CoffeeScript inherits the _actual problem_ with
JavaScript - a select few determine the introduction of language features.
Perhaps these language features are best shipped as libraries?

Maybe it doesn't matter. Perhaps most users don't need it. Or perhaps as we
continue to develop software we'll find that we'd rather defer work to the
compiler / macros and the high cost of syntax is simply not worth it.

I'm looking forward to see how 3 languages I immensely enjoy (JavaScript,
CoffeeScript, ClojureScript) co-evolve :)

~~~
btipling
> the actual problem with JavaScript - a select few determine the introduction
> of language features.

What language exists in which this is not the case? Language by committee
sounds terrible.

~~~
masklinn
> What language exists in which this is not the case?

Languages which have very little "own shape" (syntax) and let you transform it
easily (via macros) or provide high flexibility.

Mostly concatenative languages and Lisps, but e.g. Smalltalk or IO can
probably be fit in that category as well, they have a minuscule syntactic core
and that core is used to build abstractions and structures putting both the
language's designers and the language's users on a level ground.

Of course that creates other issues, where every developer or organization has
its own lingo and structures, making even going from one codebase to the next
more expensive. It's a tradeoff.

Still, realizing that you have pretty much the same power as the language
builders themselves when it comes to creating abstractions and datastructures
and control flows... is an enjoyable feeling.

> Language by committee sounds terrible.

Can end horribly, and can end pretty well. Haskell was designed by a committee
over ~10 years (FPCA '87 to the release of "The Haskell 98 Report" in 1997).

It does generally end baldy.

------
mayoff
I was going to complain that I could find no mention of TameJS (from which the
await and defer keywords/features clearly originated). Then I noticed that the
IcedCoffeeScript author is also the author of TameJS.

~~~
udp
It actually used to be called Tame, not Iced:

[https://github.com/jashkenas/coffee-
script/pull/1942#issueco...](https://github.com/jashkenas/coffee-
script/pull/1942#issuecomment-3700913)

------
mbostock
I like the generality of the defer/await concepts of TameJs (and by extension,
iced coffee). But I was curious if these concepts could be used without code
generation, as in Async.js. So I came up with Queue.js:

<https://github.com/mbostock/queue>

I haven't tried it in production code yet, but it looks like a convenient
abstraction with tunable parallelism.

------
ruxkor
Another notable feature is the generation of readable stacktraces in iced, as
explained here:

<https://github.com/maxtaco/coffee-script/blob/iced/iced.md> (search for:
"Debugging and Stack Traces")

------
patrickwiseman
Being able to syntactically assemble several parallel requests together has an
obvious advantage in making code more readable. Having a hard time wrapping my
mind around the keywords. From the examples I think more wait/collect than
await/defer. For instance:

Await these items that I want to defer.

Wait on this code block and collect these items.

------
russianbandit
Why didn't the "iced" feature just get added to CoffeeScript? Why have two
separate packages?

~~~
samdk
I haven't looked at this implementation specifically, but the issue with many
similar proposals/implementations is that the generated JavaScript is ugly.
One of the nice things about CoffeeScript is that there's no magic--it's very
easy to figure out what the generated JavaScript is doing, and there's a
straightforward CS <-> JS mapping. jashkenas (CoffeeScript's author) has been
reluctant to change that.

~~~
chc
IIRC, Jeremy Ashkenas actually brought this up in the pull request discussion,
but he sounded pretty impressed by the minimalism of the code ICS generates.
There seems to be more ideology-based opposition among the community.

------
ericskiff
It's fantastic to see so much enthusiasm and innovation happening around
JavaScript.

While I'd love to see some of these features find their way back into the core
language (or native support for coffeescript in node or browsers) it's fair to
say that's a long time off if it's ever going to happen.

In the meantime, I'm getting to massively clean up the logic and syntax of my
apps. Huge thanks to everyone working on this!

~~~
zoips
Harmony will include generators, which are basically coroutines.

------
simcop2387
The way that this manages to transform those examples makes me think that it
would make all kinds of other things more palatable than the vanilla coffee
script. I've written chains of callbacks in plain JS that this would make so
much nicer to work with.

~~~
jeswin
Can't agree more. There is no other language in the world that needs this as
badly as JS does.

\- I am hoping that this would be merged back if it could be somehow concluded
that there isn't a much cleaner way to achieve the same result. Even if the
resulting JS isn't as clean as what CS produces now. The ICS approach looks
safe; they could be assured by similar approaches in more mainstream
languages, most prominently C# (and F#) which have much bigger teams attacking
the same problems.

If the prospect of this getting merged back looks bleak, I might consider
switching ICS once I am convinced there aren't any other breaking issues.

------
equark
Why is defer needed? Why can't I follow C# and do:

    
    
       result = await search("test")
    

Is this just so that it plays nicely with non-standard callback APIs? I'd
prefer to introduce Promises (i.e., q) and have await interact with that. I
guess this is not the NodeJS way though.

~~~
crazygringo
search("test") is not an asynchronous call, in your example, because there's
no callback function. (In JavaScript)

defer() is needed because it becomes the placeholder for the callback
function, and lets Iced know how many functions it needs to wait to call back.

~~~
xpaulbettsx
In other words, JavaScript doesn't return a Promise/Future/Task<T>, so the
defer syntax is necessary. You _could_ get rid of it by simply capturing the
callback params and returning them as a value, though your code would end up
having a lot of `[0]`'s in them, since most callbacks are of the form (thing,
err)

------
Detrus
So was there more discussion about await and defer in the many github issues
on the subject? This output seems more debuggable than previous CScript defer
attempts.

~~~
chc
Here's the main one for Iced: <https://github.com/jashkenas/coffee-
script/pull/1942>

I remember there was another discussion before where they first started
talking about Max's implementation, but I can't seem to find it at the moment.
That did seem to be the general consensus, though.

------
bascule
When I made this comment the other day, I wasn't actually serious that someone
should build a JavaScript compiler that does CPS:

"CPS is also generally used as an IR in compilers, not something you write by
hand"

<http://news.ycombinator.com/item?id=3511211>

This reminds me of my Celluloid::IO system in Ruby (which uses coroutines to
provide a synchronous API), except Celluloid::IO lets you have as many event
loops as you want:

<https://github.com/tarcieri/celluloid-io>

------
olegp
If you're only using CoffeeScript on the server, then you should check out
node-fibers to achieve the same effect.

Here's an example of using my Common Node library (that implements a number of
sync APIs using fibers - <http://olegp.github.com/common-node/>) with
CoffeeScript: <https://gist.github.com/1447709>

------
quangv
When a language has dialects, you kno you are doing something right... go
coffee-script!

~~~
jnbiche
For another cool CoffeeScript "dialect", see Contracts:

<http://disnetdev.com/contracts.coffee/>

It's a great way to write defensive code for those of us who find writing
regular unit tests a little onerous even (if they are often necessary). I'm
planning on using it in all my CoffeeScript, up to -- but not including --
generated production Javascript.

------
ypcx
This is certainly a development to applaud, but for me, the most important
feature about async JS programming is to be able to catch errors in the
asynchronous code, and do it without code clutter. So I hope that if this gets
accepted to mainline CoffeScript, it will provide for a working try/catch
around the await/defer, along with caller+callee stacktraces capturing (at
least in debug mode). At that point, it will be hard for me to _not_ justify
the use of one compilation layer above JavaScript, which currently certainly
is, and even so with await/defer.

Asynchronous error handling without clutter is why I created LAEH, have a look
if you want: <https://github.com/ypocat/laeh2>

EDIT: To clarify - an uncaught error in async handler means your Node.js is
going down (unless you use the catch-all handler, which is an even poorer
practice). In browser it means your callback never returns, leaving you in
void (with a short an ambiguous stacktrace) to search where the problem is.

------
danbmil99
Nice work, I love the syntax. Was a bit disappointed at the verbosity of the
compiled js though. Wondering if the same thing could be achieved without the
secret functions, classes & variables? (Deferrals, findDeferral, __iced*...)

I think I can imagine a more direct translation of await & defer, though of
course I haven't actually tried to implement it (yet).

------
6ren
> The function defer returns a callback, and a callee in an await block can
> fulfill a deferral by simply calling the callback it was given.

I'm wanting in CoffeeScript knowledge and/or intelligence, so could someone
explain the above please? (In the examples, _defer_ seems to specify the
variable that gets the result of _await_.)

~~~
phzbOx
I tried to formulate very differently so you can see that as another point of
view. Sorry for the lack of formality.

 _defer_ is a function which returns another function. When _that returned
function_ is called, we get out of the await block.

So, to take the same example:

    
    
      await 
        for k,i in keywords
          search k, defer out[i]
    

Here, defer(out[i]) returns a function. We pass this function to search.

Search is like this:

    
    
      search = (keyword, callback) ->
        # do some search
        callback(some_result)
    

And here, by calling _callback_ , which is the _function returned by defer_ ,
it will end the await block.

Here's a trivial example:

    
    
      await
        some_function = (fn) -> fn(1234)
    
        some_function(defer(x))
        console.log(x)
    

defer(x) returns a callback, it's given to _some_function_. And
_some_function_ calls it, which ends the await block.

~~~
6ren
Thank you for your thoughtful answer, it's clarified some issues. I'm afraid
it also raises more questions for me (I probably need to go study CoffeeScript
some more). BTW, the text I added is actually from the first example - the
simplest:

    
    
      await $.getJSON url, defer json
    

Is the following right? Syntactically, "defer json" is an argument to the
function "$.getJSON". So you could write it like this:

    
    
      await $.getJSON( url, defer(json) )
    

The code we are waiting for is the "$.getJSON" call. That code indicates that
it is finished by calling _the function returned by defer_.

But what does _the function returned by defer_ do? It looks like it (somehow)
sets its argument to the result... so in the above example, "json" (somehow)
gets the result of the call; in your example, "x" (somehow) gets a value. I'm
guessing it's some convenient compiler magic that ICS does, and not an issue
of CoffeeScript syntax.

An upshot of this is you can't give defer any old argument (e.g. a numerical
value) - it has to be a variable that is capable of being set.

Also, who is the "callee"? A "callee" is a function that is called... Oh, does
it mean (eg) "$.getJSON" is a callee, and it calls the callback function given
to it (in the jQuery docs, it's notated as " _success(data, textStatus,
jqXHR)_ "; here, that _success_ function is _the function returned by defer_
). I guess, given the purpose of ICS, there will always be a callee in the
block - but it seems to me that, syntactically, you could just directly call
_the function returned by defer_. Ah... but (I bet) part of the compiler magic
is that you are only allowed to call _the function returned by defer_ from
within another function - this is because the result of that other function is
needed in order to set the argument of defer to it. Whew.

One last thing: the description talks about "deferrals" begin "fulfilled", but
it doesn't say where these defarrals come from. Now, I think they are created
by calling _defer_.

Hmmm.... it's probably better for me to think about this in terms of lisp
macros, instead of C calls, as macros allow you to do weird source code
transformations, like setting the value of a variable given as an "argument".
i.e. ICS is a macro.

~~~
phzbOx
Note that I haven't tested ICS so it's only based on my understanding of the
examples/docs.

"Is the following right? Syntactically, "defer json" is an argument to the
function "$.getJSON". So you could write it like this: await $.getJSON( url,
defer(json) )"

Yes, exactly.

"'m guessing it's some convenient compiler magic that ICS does"

Yes, exactly. When you say "defer(x)", it basically returns a callback like
this:

    
    
      function(result) {
        *x = result;
        Code to terminate the await block*
     }
    

"One last thing: the description talks about "deferrals" begin "fulfilled",
but it doesn't say how they are created. Now, I think they are created by
calling defer."

Yeah, defer returns a callback and when you call it, it "fulfills" the await,
i.e. you tell await that you're done with that async block.

~~~
6ren
Thanks a second time, I'm getting there! I realized one can look at the
transformed javascript output, to see just what it does. The setting of the
variable in the _defer_ becomes:

    
    
      $.getJSON(url, __iced_deferrals.defer({
          assign_fn: (function() {
            return function() {
              return json = arguments[0];
            };
          })(),
          lineno: 6
        }));
    

Presumably, when the function that ___iced_deferrals.defer_ returns is called
by the code in .getJSON that delivers the result, it will set _arguments[0]_
to that result, and then call the _assign_fn_ above. This will set json to
that result.

Also, I realize that it doesn't set _json_ to the returned value of
_$.getJSON_ , as _$.getJSON_ doesn't return anything - it uses a callback to
deliver its result. It seems that ICS always works this way - which I guess
implies that the use-case it's for always uses callbacks...

BTW: I'm not sure why the above has a function which is then called
immediately. Maybe a coffeescript thing, for separating namespaces? I assume
the _lineno: 6_ is for debugging - I recall some debate against this. Good to
see it got in.

~~~
phzbOx
About the function which is called automatically, it's a common pattern in
javascript. It's used to create a new _namespace/modules_ as block are defined
per function instead of {}.

And, you are right that we're not assigning the return value of $.getJSON.
Basically, once $.getJSON has finished with the request, it will call a
function with the result. _This result_ is set to the variable passed to
_defer_. It's a bit of a brain teaser but that's the whole point of the
await/defer thingy. Instead of using a callback to retrieve the result as an
argument, you just write a variable after defer and you receive it.

------
jarek-foksa
If I understand correctly, everything after "await ..., defer" block will be
executed only after the asynchronous operations from the await block are
completed.

Does it mean that it's impossible to return any value from a function that
contains await block?

    
    
      module = 
        dataPath: "http://search.twitter.com/search.json?q=blah&callback=?"
    
        init: () ->
          # Fetch data and do some stuff with it
          await 
            $.getJSON @dataPath, defer @data
      
          # Return yourself (this won't work)
          return @

~~~
timruffles
There is a way around it. Here, everything after the await is transformed into
a callback for the await magic:

    
    
        waity = (forFn) ->
          await forFn defer r1, r2
          console.log "values of defer variables", r1, r2
          return "this only returns from the result callback, not waity"
    
        syncReturn = waity (cb) ->
          setTimeout ->
            cb "r1 val", "r2 val"
    
        console.log "waity's synchronous return value:", syncReturn
    

So our output is:

    
    
        waity's synchronous return value: undefined
        values of defer variables r1 val r2 val
    

To return, you can simply write:

    
    
        waity = (forFn) ->
           setTimeout -> 
             await ...
           return "works as normal"

------
6ren
Just on the website itself: it's very impressive presentation and usability
for playing with examples. Couple of issues:

1\. The floating title looks cool esp with greying out above it, but it page-
down/space moves down more than a page (in effect), so it skips some text. I
didn't realize I was missing some text for a while.

2\. In the Animal example, the "Run" button doesn't work (though "run" works
from the "load" overlay for it). I'm uising Firefox 9.0.1 on Ubuntu 10.04

------
goblin89
Awesome! I'm wondering whether using jQuery's deferreds can give close to same
advantages.

Looking at first parallelSearch example, it could be like that (in regular
CoffeeScript):

    
    
      parallelSearch = (keywords, cb) ->
        searches = [search k for k in keywords]
        $.when.apply(searches, null).then cb
    

Although seems like it can't really cover all Iced's use cases. Hopefully the
fork will continue to be maintained!

------
nailer
The aim of your docs should be to show how simple and readable
IcedCoffeeScript is: using multi character variable names in your examples
would help to achieve that.

~~~
tsuraan
When you see a two-liner of

    
    
      for k, i in keywords
        search k, defer out[i]
    

Do you really get lost or confused? Are you actually complaining about a
problem, or just a violation of your favorite style guide? Personally, I'm
looking for what makes IcedCoffeeScript unique; all else is just cruft, so
keeping that terse is just fine with me.

~~~
nailer
Yes, I lose a few milliseconds. You'll notice your example had to include the
loop for 'search k' to have any meaning, so I suspect you did too.

~~~
kstenerud
I'm still confused. Are those key-value pairs? What is "i" actually doing?

~~~
bricestacey
k is the value, i is the index.

------
ewrgsdfg
What this really needs is some simple example code for Use Cases :)

------
taskstrike
This is awesome

