14 ms·
IcedCoffeeScript
- mayoff 15y agoI 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 15y agoIt actually used to be called Tame, not Iced: https://github.com/jashkenas/coffee-script/pull/1942#issuecomment-3700913 https://github.com/jashkenas/coffee-script/pull/1942#issueco...
- deleted 15y ago[deleted]
- adam_freidin 15y agome too. but you'ld think that it would help to at least say somewhere (like a subtitle in the banner) "tame + coffeescript"
- Detrus 15y agoSo 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 15y agoHere's the main one for Iced: https://github.com/jashkenas/coffee-script/pull/1942 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.
- russianbandit 15y agoWhy didn't the "iced" feature just get added to CoffeeScript? Why have two separate packages?
- samdk 15y agoI 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.
- deleted 15y ago[deleted]
- chc 15y agoIIRC, 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.
- danbmil99 15y agoI did some simple tests, and frankly the generated code is ugly, certainly by comparison to vanilla CS. Gone is the "oh I see how it did that, it's just a Javascript version of my Coffee!" It's now more like what C++ used to look like when compiled to C (remember cfront? probably not. Be glad you don't). As someone else said, if you avoid await/defer entirely, it seems to back off to exactly what Coffeescript does, so there is a nice progression path. code: https://github.com/danx0r/testiced#readme https://github.com/danx0r/testiced#readme
- raganwald 15y agoThis is a fork of the language, not an official feature. It’s as if you wrote your own version of JavaScript that trampolines function calls and performs tail-call optimization. You still need to go through the social process to get your ideas into the main “trunk.” Selling people on adopting your fork might be one way to get everyone excited about the idea. That being said, right up front he explains the two reasons why this is a departure from CoffeeScript’s core philosophy: `await` and `defer` are changes in the semantics of JavaScript, and not surprisingly, code written in IcedCoffeeScript no longer compiles into more-or-less recognizable JavaScript. Modulo syntax and sugar, CoffeeScript is JavaScript with some minor changes to the AST (such as soaking up nils with the Elvis operator). IcedCoffeeScript is another language that evolved from JavaScript and transpiles to JavaScript. Before adding such features willy-nilly to CoffeeScript, folks need to be comfortable walking away from a core value. I’m not saying that’s a bad thing, but it’s a problem related to the Innovator’s Dilemma: To embrace this new value, CoffeeScript will have to alienate some portion of its user base that value compiled JavaScript that is easily recognizable to anyone who has read the CoffeeScript source.
- deleted 15y ago[deleted]
- simcop2387 15y agoThe 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 15y agoCan'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.
- nailer 15y agoThe 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 15y agoWhen 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 15y agoYes, 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 15y agoI'm still confused. Are those key-value pairs? What is "i" actually doing?
- bricestacey 15y agok is the value, i is the index.
- bascule 15y agoWhen 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 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 https://github.com/tarcieri/celluloid-io
- patrickwiseman 15y agoBeing 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.
- equark 15y agoWhy 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 15y agosearch("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 15y agoIn 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)
- ruxkor 15y agoAnother notable feature is the generation of readable stacktraces in iced, as explained here: https://github.com/maxtaco/coffee-script/blob/iced/iced.md https://github.com/maxtaco/coffee-script/blob/iced/iced.md (search for: "Debugging and Stack Traces")
- quangv 15y agoWhen a language has dialects, you kno you are doing something right... go coffee-script!
- jnbiche 15y agoFor another cool CoffeeScript "dialect", see Contracts: http://disnetdev.com/contracts.coffee/ 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.
- mbostock 15y agoI 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 https://github.com/mbostock/queue I haven't tried it in production code yet, but it looks like a convenient abstraction with tunable parallelism.
- swannodette 15y agoThis 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 15y ago> 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.
- pufuwozu 15y agoClojureScript (which swannodette works on). You can invent your own language features in a Lisp.
- jberryman 15y agoHaskell was designed by committee.
- masklinn 15y ago> 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.
- taskstrike 15y agoThis is awesome
- 6ren 15y ago> 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 15y agoI 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 15y agoThank 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.
- 6ren 15y agoJust 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 15y agoAwesome! 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!
- ericskiff 15y agoIt'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 15y agoHarmony will include generators, which are basically coroutines.
- danbmil99 15y agoNice 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).
- skeptical 15y agoCould anybody enlighten me. Was a fork of CS the only way to achieve this? Forking a programming language is a pretty radical thing.
- jarek-foksa 15y agoIf 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 15y agoThere 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"
- olegp 15y agoIf 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/ http://olegp.github.com/common-node/) with CoffeeScript: https://gist.github.com/1447709 https://gist.github.com/1447709
- ypcx 15y agoThis 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 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.
- ewrgsdfg 15y agoWhat this really needs is some simple example code for Use Cases :)