one part i'm ambivalent about though is assignment and conditionals. there are too many ways to do the same thing, and i sit there wondering whether i'm using the "right" one.
The slides didn't make a lot of sense (to me) without some sort of commentary. I presume from the title I'm not supposed to be familiar with the language.
This was a talk given by Tim at the JavaScript User Group Meeting Berlin in May 2010. There is also a video of the talk, but I can't find that anymore.
This is what, attempt number seven hundred and fifty two to create a mainstream language that encourages functional programming?
Incidentally, what's the most successful recent language that tries to make functional programming terser by not having an explicit "return" keyword (everything's an expression)? I'm genuinely curious, and don't think any significantly great number of programmers will ever find this style easier.
Is "square: (x) -> x*x" more modern syntax, or simply more functional? It surely isn't a new idea, maybe as old as Lisp, and a number of other new languages are explicitly imperative.
I'm glad you picked out "everything is an expression" as the characteristic feature. I think that's completely correct -- everything else in the language is carefully compiled to make its use as part of a larger expression possible.
I don't, however, think that it's about functional programming. It's about flexibility: if everything is an expression, you can use any bit of code in relation to any other, and not worry about what parts of the languages are merely statements ... a JavaScript example being "var a = b", which cannot be used as part of a larger computation.
Having every function return a value is something that seems extraneous at first look, but ends up encouraging good API design. From the point of the caller of the function, returning a meaningful value is always appreciated -- even if it's as simple as returning "true" to acknowledge that the operation was completed successfully.
I've been using CoffeeScript the last few weeks (writing a library using Raphael) and I'm really enjoying it. My one complaint is that the documentation has a few holes - in particular, it took me a little while to work out how to do block comments (### on either end), and more importantly, there's nowhere near enough documentation on cake. Right now my Cakefile uses child_process.exec, which is kind of lame and also doesn't show compilation errors.
Thanks for the documentation tips -- it's always helpful to hear what's missing from the perspective of a pair of fresh eyes. I've updated the documentation with an example of block comments:
And extended the section on "cake" a little bit with a better example that demonstrates passing in a command-line option. It sounds like your problem is different though -- here's the Node.js docs for child_process.exec:
You can use the "stderr" argument in the callback function to print the child's error output to the console. Running this bit of CoffeeScript, for example, will print out "to stderr":
Thanks Jeremy. I don't particularly want to use child_process.exec if there's a better/more direct way to compile, which it seems like there must be. I think it would be really helpful to have a dead simple Cakefile example for compiling a single CS file into a single JS file. It's not clear to me what the standard way to do that is, even with your new example.
I wouldn't say that JavaScript is "perfectly good." For instance, the statement "i=0" declares a global named i, unless there's a "var i" statement in a closer scope. It's a very, very easy mistake to make, and can lead to hours of debugging.
JavaScript is good, but CoffeeScript removes many of its imperfections, as well as offering a far better syntax.
Any time I have to reach for an external tool to figure out what's wrong with my program, I wonder if the language/framework/library/whatever could be improved to help prevent the problem in the first place. Valgrind much?
I'll never understand why some people are so opposed to learning new languages, especially one which won't change your current ecosystem and greatly improve your life (and quickly).
As a source-to-source language, we try to keep debugging sane by outputting pretty-printed JavaScript that shouldn't be too hard to debug. For example, dropping you right into the middle of the JavaScript that's generated for the CoffeeScript Lexer looks like this:
Pretty readable. You can use a Webkit or Firebug debugger just as you would with normal JS. It's a golden rule (with one small exception) that there are no CoffeeScript-specific constructs or special functions added to the runtime, no matter how tempting it might be to do so.
The single largest headache in practice is having to refer to the generated JS if the exception is vague, and just includes a line number. But I'm not sure that there's anything we can do to mitigate that, other than to keep the JS readable...
The debugging experience is surprisingly good. CoffeeScript is pretty much a one-to-one conversion into JavaScript. This makes it easy to work out which line of JavaScript was generated by which line of CoffeeScript, and debug the CoffeeScript directly.
I find I don't often need to look at the compiled JavaScript very often, but it is perfectly readable to do so if required.
I thoroughly hated that ignorant, nasty slide show displaying piece of crap used to present the stuff. It kept wresting control away from me so I couldn't view the slides at my own pace. What ever happened to text on a page, dammit?
if the OA would have just been plain text/images in HTML then everyone would get fast clutter-free with any web client, any platform, with less code, less complexity, etc.
It took me a while to learn to never hit the play button on slideshare. Always use the forward and back buttons next to play and you can advance at your own pace. Quite annoying.
I've found the combination absolutely brilliant -- it recalls Ruby's creator Matz's promise of a language to "make programmers happy".
You get the expressiveness and brevity of Ruby, plus first-class functions, running in anyone's browser; and you get really well-thought-out event handling, AJAX and animation APIs.
I have only one serious pain-point with CoffeeScript: the Pythonesque significant whitespace. This commonly trips me up when providing anonymous function arguments to other functions (very common when assigning event listeners, for instance).
I guess the problem is that I never really understand exactly which whitespace is going to be deemed significant -- so maybe it's just a matter of documentation?
If you can show me a couple examples of places where the indentation tripped you up, I'd love to fix the documentation to explain them. Either starting a ticket, or gist-ing the examples here would be fine.
There was a question in #coffeescript last night about passing multiple anonymous functions into a function, and we came up with a couple of nice ways to write it:
The "try coffeescript" demo (http://jashkenas.github.com/coffee-script/) is really cool. It converts to javascript in realtime/as you type, including error checking on the fly.
I like the lambda syntax (I don't recall seeing exactly this syntax before):
() -> alert("lambda")
(() -> alert("lambda")) () # to call it
It's a matter of opinion, but I don't particularly like when you can "omit" things.. and sometime it works and sometime it doesn't. Yes, sometime it makes the code a little clearer, but it can often lead to sneaky bugs and confusion.
it also increases the friction when you are editing; the question in your mind must be "does this edit require the implicit to be made explicit?" Editor support can help alleviate the drudgery of the change, but I prefer to pay up-front.
aaronblohowiak, I wonder if "pay up front" is analogous to pre-mature optimization?
I'm thinking out loud, mainly because I tend to use the simplest syntax possible when coding in languages that allow for multiple syntaxes (i.e., Ruby). Most of the time, my decisions (at least) work out for me, and I don't have to go back and (say) add parentheses.
My two cents on optional parentheses, optional commas, and optional syntax in general are that it's about readability and style. If the statement that you're writing isn't clear without disambiguating the structure, then by all means, use parentheses. But if you're choosing between this:
print("Hello");
And this:
print "Hello"
(Which are equivalent in CoffeeScript) ... I'll take the latter every time.
In general, the compiled code should pass JavaScript lint without errors, and can be compatible with ECMA5 strict mode, but does not enforce it (because strict mode has a lot to do with runtime implementation, which we can't do anything about). Looking at page 233 of the spec:
Most of the strict mode restrictions have to do with "arguments" and "eval", which CoffeeScript doesn't affect. The two bits that we do enforce are: "Assignment to an undeclared identifier or otherwise unresolvable reference does not create a property in the global object," and "Strict mode code may not include a WithStatement" -- the former because variable scoping is automatic, and the latter because there is no "with" statement in CoffeeScript.
But there are a number of other, more important bad parts that are omitted, beyond strict mode: JavaScript's string-based switch statement, coercive equality checks, named function statements, trailing commas, and so on...
Just wrote an API in CoffeeScript, using Node.js and Express.
It was surprisingly enjoyable. I can see this ecosystem giving Rails/Sinatra/Django a real challenge. CoffeeScript makes ssjs a lot easier once you get used to it, Node.js gives you free non-blocking/high concurrency, and Express, which just released 1.0, is quickly maturing into a really solid DSL/web framework.
I'm excited to see how the judicious use of JavaScript will evolve webapps beyond the Rails/Sinatra/Django paradigm, and allow you to share the code for your application between the client and the server. V8/Node.js is just the cherry on top:
Thanks to the effort put in by the V8 team, JavaScript is now an order of magnitude closer to C speed than Ruby, Python, and Perl, and sits at the same tranche of performance as OCaml and Go.
I'm working on a project that will let you share the same view code between rails, node and browsers. email me if this is something that you'd like to hack on (or check my github)
EJSRB is a full javascript context, and javascript is a language you probably already know. While our views are separate from controllers and models, they often need more advanced string manipulation than liquid or mustache give you. The fact that it is a full javascript context means you can define your own helpers, and have them still work on the client side. For instance, say you want to generate element ids from the json data. This belongs in a function that is accessible to your view layer, but you shouldn't have to program this twice (once for server, once for client.) AFAIK, there isn't a great way to accomplish this code sharing yet.
The really interesting language in that comparison is LuaJIT. It is faster and more concise than Javascript. It's sad that a mature, small, concise language like Lua doesn't have more traction outside niches.
I really enjoy working with Lua, though the opportunities have been infrequent. While Node.js looks like a wonderful piece of technology, every time I hear about it I feel a bit bitter that yet another opportunity to popularize Lua has been missed.
But the one battery that is included in JS makes it unavoidable, and most programmers (the kind that don't read HN or proggit) are the kind to not want to learn another language. If you have the choice between using the quirky thing you know or learning something else, its a good bet most programmers will choose to use the tool the know, quality of the respective tools be damned ;)
JS absolutely has its faults, and you can hope all you want. But just by the simple fact that JavaScript is supported in every popular browser, and the browser is the largest application platform on the planet, means JS will soon to be the defacto standard language. Server & client-side.
It's syntactic sugar for multiline strings. It lets you write out formatted blocks of text that preserve indentation, allow you to use double-quotes and single-quotes inside without escaping, and because we have ECMA Harmony-style string interpolation -- you can interpolate values into heredocs as well.
For example, here's a hypothetical message:
email: """
Dear $recipient,
You should receive your $product
in the mail in $product.eta days.
Thanks,
$sender
"""
That's really nice, I would love that both for the above use of multiline text to be printed. But especially for client-side html templates.
I'm building my own javascript preprocessor language called O. I will definitely have to use that one, I hadn't thought of adding that. Should have considering it's in PHP, Pything, etc.
ps. I like the look of coffeescript, and the principle of having everything be an expression. What other kinds of properties does it enforce? Are you going to be adding any more features/property-preservations?
I'm trying to shoot for two interesting properties, 1) To be able to compile it back down to C/C++ for server side speed increases(Say in projects like Node.js where you can pretty easily hook in C/C++ modules. 2) To have the property of all code be reversable, and branchable for some interesting use cases. The reversability ties into some Networking/User-Interface Libs I'm making.
I'm curious what kind of tricks you used for implementing Coffeescript. Did you use hand made parsers, Parsing Expression Grammars, or base it on any other good projects?
Compiling a single language into JavaScript source code as well as C or C++ is going to be one hell of a trick. I think it'll be very difficult to keep the semantics the same, without resorting to running the equivalent of a JavaScript interpreter inside of your C++, but I wish you the best of luck with it.
If you'd like to discuss the implementation, feel free to drop by #coffeescript on freenode. But to give you the rough outline -- the compiler is made up of (in order), a Lexer, Rewriter, Parser, and AST of Nodes. The lexer creates the tokens, the rewriter rewrites the stream of tokens, disambiguating parses and allowing for optional syntax, the parser generates the AST of nodes, and then "compile()" is called on the root node, and walks down the tree, compiling the JavaScript string recursively.
For the parser, I'm using the excellent Jison parser generator for JavaScript, in LALR(1) mode. The only really unorthodox part of this is the Rewriter. It's not kosher to munge a token stream before parsing it -- but it's removed a ton of complexity from the grammar to not ever have to handle the syntactical edge cases, and to have them resolved in advance. All of the source is annotated, so here's some links:
You are totally correct about the C/C++ generation not being easy if I go for making the whole language be elegantly compilable. I was thinking more of a subset, where you can mark a module or function(Not sure about the granularity) and it would raise a compile error if it doesn't maintain semantics that work elegantly in both Javascript and C/C++. It's really to allow Javascript programmers to not have to learn C/C++ and be able to accelerate their server side code (For say large image, or file processing. Or just expensive calculations like Pathfinding or Search-Space type stuff.) Of course it only works elegantly for server side, but it would be future proof for say using Native Client on the client side when or if it becomes available.
Thanks for the pointers, I remember now finding those implementation details when I leafed through your code a while back.
I'll check out the freenode channel when I get a chance.
I'm sold. Does it have a translator for all my old js, like sass-convert? And can I set it to watch a directory for changes and recompile if I save a file, like "compass watch"?
It doesn't have a translator from JS to Coffee, I'm afraid. There isn't a one-to-one mapping (ie. detecting when you're actually using a for loop as an array comprehension).
As for watching a directory for changes, absolutely. Just pass "--watch" to the "coffee" executable. For example:
I've been working with coffeescript all evening and I'm loving it. My one suggestion/complaint so far is that you should follow Python more closely in refusing to accept an assignment in conditionals and insisting on comparisons only, because it eliminates a lot of bugs. E.g. if I type
Glad you mentioned that point. The distinction between '=' and '==' in most programming languages is a personal pet peeve of mine. I think that it confuses two separate issues: labeling a value with a name, and testing the equality of values. Terrifically confusing stuff if you're coming from algebra.
So, although '=' is available to make transitioning from other languages smoother, idiomatic CoffeeScript would use ':' for assignment, both within and outside of object literals, and would use 'is' for equality. Harder to make a bug out of:
77 comments
[ 3.8 ms ] story [ 114 ms ] threadone part i'm ambivalent about though is assignment and conditionals. there are too many ways to do the same thing, and i sit there wondering whether i'm using the "right" one.
Incidentally, what's the most successful recent language that tries to make functional programming terser by not having an explicit "return" keyword (everything's an expression)? I'm genuinely curious, and don't think any significantly great number of programmers will ever find this style easier.
(Technically Ruby does have a return keyword, but it's optional. Same goes for CoffeeScript, I believe.)
But you are quite right that Perl if/else are statements and not expressions. Instead you can use the ternary operator:
And because of ditto for Perl you can also do following:I don't, however, think that it's about functional programming. It's about flexibility: if everything is an expression, you can use any bit of code in relation to any other, and not worry about what parts of the languages are merely statements ... a JavaScript example being "var a = b", which cannot be used as part of a larger computation.
Having every function return a value is something that seems extraneous at first look, but ends up encouraging good API design. From the point of the caller of the function, returning a meaningful value is always appreciated -- even if it's as simple as returning "true" to acknowledge that the operation was completed successfully.
Let me see, Ruby, Haskell and Scala uses this syntac.
http://jashkenas.github.com/coffee-script/#heredocs
And extended the section on "cake" a little bit with a better example that demonstrates passing in a command-line option. It sounds like your problem is different though -- here's the Node.js docs for child_process.exec:
http://nodejs.org/api.html#child_process-exec-95
You can use the "stderr" argument in the callback function to print the child's error output to the console. Running this bit of CoffeeScript, for example, will print out "to stderr":
http://jashkenas.github.com/coffee-script/documentation/docs...
JavaScript is good, but CoffeeScript removes many of its imperfections, as well as offering a far better syntax.
http://github.com/jashkenas/coffee-script/blob/master/lib/le...
Pretty readable. You can use a Webkit or Firebug debugger just as you would with normal JS. It's a golden rule (with one small exception) that there are no CoffeeScript-specific constructs or special functions added to the runtime, no matter how tempting it might be to do so.
The single largest headache in practice is having to refer to the generated JS if the exception is vague, and just includes a line number. But I'm not sure that there's anything we can do to mitigate that, other than to keep the JS readable...
I find I don't often need to look at the compiled JavaScript very often, but it is perfectly readable to do so if required.
I've found the combination absolutely brilliant -- it recalls Ruby's creator Matz's promise of a language to "make programmers happy".
You get the expressiveness and brevity of Ruby, plus first-class functions, running in anyone's browser; and you get really well-thought-out event handling, AJAX and animation APIs.
I have only one serious pain-point with CoffeeScript: the Pythonesque significant whitespace. This commonly trips me up when providing anonymous function arguments to other functions (very common when assigning event listeners, for instance).
I guess the problem is that I never really understand exactly which whitespace is going to be deemed significant -- so maybe it's just a matter of documentation?
There was a question in #coffeescript last night about passing multiple anonymous functions into a function, and we came up with a couple of nice ways to write it:
http://gist.github.com/479249
I should have mentioned that's the other thing to love about CoffeeScript: insanely responsive support!
I like the lambda syntax (I don't recall seeing exactly this syntax before):
I mean:
map x -> xx seq
might be readable ..
but:
map x -> xx seq seqs
is less clear.. while:
(map (x -> x*x) (seq seqs)) is more readable.
I'm thinking out loud, mainly because I tend to use the simplest syntax possible when coding in languages that allow for multiple syntaxes (i.e., Ruby). Most of the time, my decisions (at least) work out for me, and I don't have to go back and (say) add parentheses.
Did the language remove any of the "bad parts"?
http://www.ecma-international.org/publications/files/ECMA-ST...
Most of the strict mode restrictions have to do with "arguments" and "eval", which CoffeeScript doesn't affect. The two bits that we do enforce are: "Assignment to an undeclared identifier or otherwise unresolvable reference does not create a property in the global object," and "Strict mode code may not include a WithStatement" -- the former because variable scoping is automatic, and the latter because there is no "with" statement in CoffeeScript.
But there are a number of other, more important bad parts that are omitted, beyond strict mode: JavaScript's string-based switch statement, coercive equality checks, named function statements, trailing commas, and so on...
It was surprisingly enjoyable. I can see this ecosystem giving Rails/Sinatra/Django a real challenge. CoffeeScript makes ssjs a lot easier once you get used to it, Node.js gives you free non-blocking/high concurrency, and Express, which just released 1.0, is quickly maturing into a really solid DSL/web framework.
I'm excited to see how this ssjs scene unfolds.
http://shootout.alioth.debian.org/u32/code-used-time-used-sh...
Thanks to the effort put in by the V8 team, JavaScript is now an order of magnitude closer to C speed than Ruby, Python, and Perl, and sits at the same tranche of performance as OCaml and Go.
http://github.com/aaronblohowiak/ejsrb/
I think that the usual way to share views between different languages is to use a language-agnostic templating engine, like Mustache, or Liquid.
How does EJSRB differ?
Furthermore, they are not really trying to promote the language beyond its current niches.
That said, there are good third party libraries and frameworks, and a Rubygems-like system called Lua Rocks.
The fact that Javascript is an in important feature in software that everyone runs is a whole different kind of advantage.
For example, here's a hypothetical message:
I'm building my own javascript preprocessor language called O. I will definitely have to use that one, I hadn't thought of adding that. Should have considering it's in PHP, Pything, etc.
ps. I like the look of coffeescript, and the principle of having everything be an expression. What other kinds of properties does it enforce? Are you going to be adding any more features/property-preservations?
I'm trying to shoot for two interesting properties, 1) To be able to compile it back down to C/C++ for server side speed increases(Say in projects like Node.js where you can pretty easily hook in C/C++ modules. 2) To have the property of all code be reversable, and branchable for some interesting use cases. The reversability ties into some Networking/User-Interface Libs I'm making.
I'm curious what kind of tricks you used for implementing Coffeescript. Did you use hand made parsers, Parsing Expression Grammars, or base it on any other good projects?
If you'd like to discuss the implementation, feel free to drop by #coffeescript on freenode. But to give you the rough outline -- the compiler is made up of (in order), a Lexer, Rewriter, Parser, and AST of Nodes. The lexer creates the tokens, the rewriter rewrites the stream of tokens, disambiguating parses and allowing for optional syntax, the parser generates the AST of nodes, and then "compile()" is called on the root node, and walks down the tree, compiling the JavaScript string recursively.
For the parser, I'm using the excellent Jison parser generator for JavaScript, in LALR(1) mode. The only really unorthodox part of this is the Rewriter. It's not kosher to munge a token stream before parsing it -- but it's removed a ton of complexity from the grammar to not ever have to handle the syntactical edge cases, and to have them resolved in advance. All of the source is annotated, so here's some links:
* Jison: http://github.com/zaach/jison
* Lexer: http://jashkenas.github.com/coffee-script/documentation/docs...
* Rewriter: http://jashkenas.github.com/coffee-script/documentation/docs...
* Grammar: http://jashkenas.github.com/coffee-script/documentation/docs...
Thanks for the pointers, I remember now finding those implementation details when I leafed through your code a while back.
I'll check out the freenode channel when I get a chance.
As for watching a directory for changes, absolutely. Just pass "--watch" to the "coffee" executable. For example:
Which will watch "src" for changes, and compile all ".coffee" files inside to ".js" files in "lib", preserving the directory structure.So, although '=' is available to make transitioning from other languages smoother, idiomatic CoffeeScript would use ':' for assignment, both within and outside of object literals, and would use 'is' for equality. Harder to make a bug out of: