12 ms·
A Case Against Using CoffeeScript
- cheald 15y agoThe increase in debugging complexity is a fair point, and it does add an extra step in between finding a problem and fixing it. However, in practice, I'm not sure I've ever had this be a major problem; I've had more problems related to bad error messages from the Coffeescript compiler (generally due to significant-whitespace errors) than I have had in trying to associate Javascript to its source Coffeescript. The rest of the examples, though, don't hold much water. The takeaway from them is "it's possible to write terribly-factored code, even in a pretty language". doSomething() if five and six and seven Can be rewritten as this, if it's more comfortable for you: if (five && six && seven) then doSomething() !=, &&, ||, (), and the like are still usable in Coffeescript. If it makes the code easier to read, then use them! The whole concern with list comprehension syntax order is sort of a red herring - it works that way in Javascript 1.8, as well! In fact, nearly every language that implements list comprehension does it similarly. 160-column 1-liners are evil in any language, not just Coffeescript. If you don't like the "method, loop, condition" syntax of list comprehensions, that's a problem with list comprehensions, not with Coffeescript. The points about the implicit returns and parentheses-less calls apply, as well. When it makes sense to explicitly use them for code clarity, use them. For example, your confusing getUser method can be easily written as: getUser = (id) -> url = "users/#{id}" dfd = $.ajax( url: url format: 'json' method: 'get' ) return { url: url, promise: dfd.promise() } Voila, it's still coffeescript, and it's very readable, easy to understand, and not at all difficult to maintain. The fat arrow, like the rest of the examples, is yet-another-case of "Yes, you can shoot yourself in the face with it, if you abuse it". Event binding isn't the only case when you need to preserve scope! Sometimes (frequently, even) you need to pass around an anonymous function bound to a specific scope. The fat arrow is explicitly for that sort of work. If you abuse it every time you could otherwise just call call() or apply() (because you have access to the scope to invoke the function on, in addition to the function itself), then yeah, it's bad. Have you even looked at the implementation of $.proxy() used in your examples there? Guess what it does? It creates a new anonymous function, binds it to the passed-in scope, and returns it. Which is exactly what the fat arrow does in Coffeescript. Why is it evil in Coffeescript, but okay in jQuery? Because you aren't aware it's happening? Your "This is how you should do it" method in Coffeescript is wrong. It should be something like this: widget = attach: -> @el.bind 'click', @handler handler: (event) => doStuffWithThis() That's clearer than any of your examples, Just Works, doesn't have a jQuery dependency, and is even less code than your corrected example. First-class functions have the `this` problem in every language, and the fat arrow is very nice syntactic sugar for what you have to do anyway. The purpose of Coffeescript is to make your life as a Javascript developer easier. If you're using it to make your life harder, you're doing it wrong. It's not a case against using Coffeescript - it's a case against writing terrible code.
- IsaacSchlueter 15y agoI think part of the gist of the article was that abused CoffeeScript is more bad than abused JavaScript. So, yes, of course, you can do everything differently. But the point is, in the moment when writing it, it's not confusing, and doesn't stand out as a bad thing. Later, when you look at it, it IS confusing.
- cheald 15y agoI dunno. I think that a lot of that is just a matter of developer maturity and code discipline. If you can't recognize a code smell when you're writing code, the problem is probably that you aren't mature enough as a developer, not that the language is bad for allowing it. I don't think that most seasoned developers would look at that 160-column list comprehension, say "okay, that works!" and move on to the next task. They'd say "okay, that works, but holy crap it's ugly. Quick, to the refactormobile!" I've seen 160+ column nested ternary operations in pure Javascript that make the aforementioned comprehension look positively poetic. I've seen some genuinely horrible Javascript. Like, stuff that so terribly abuses the language without any comprehension whatsoever of closures or context binding and only works because the author got stupidly lucky and/or abused globals so badly that the code was effectively one giant function. In both cases, bad developers writing bad code are going to produce unmaintainable messes. Doesn't mean that the language should be avoided. Garbage in, garbage out.
- ryanflorence 15y agoThe code smells are on the demo page for CoffeeScript.
- cheald 15y agoWhich bits do you consider to be code smells, out of curiosity? Things like postfix conditionals and list comprehensions generally aren't considered to be smells by the majority of people that use them. I don't see any 160-column list comprehensions or implicit bracketless object returns there, which are genuine smells.
- chc 15y agoThe debugging complaint is valid, but a) doesn't generally seem that troublesome in practice (especially given the still-crude state of JavaScript debugging tools in general), and b) will be a lot less valid in the near future, as WebKit, Google and Mozilla are all adopting support for alternative languages in their respective JavaScript implementations IIRC.
- ryanflorence 15y agoGo ahead and [do this horrible thing], it's not _that_ bad. > especially given the still-crude state of JavaScript debugging tools in general I feel like people don't know how to use web inspector... There will never be native CoffeeScript, you will always debug the JavaScript.
- jjm 15y ago"There will never be native CoffeeScript" Sure, but we'll learn from CoffeeScript and apply it to the next ECMA ver. The CoffeeScript discussion is a worthy one, but declaring it unworthy to have a seat at said table prevents progress. I'd rather read articles on how to make things better instead of bashing.
- chc 15y ago> Go ahead and [do this horrible thing], it's not _that_ bad. Sure. Let me insert a few things that can have really bad side effects that I still think you should do: • Leave your house every day (car crashes ROFLstomp homicide as a cause of death) • Eat food (most foods have some ill effect on your body) • Write some code in C (it's a very unsafe language, but sometimes necessary) • Use a computer (hurts your eyes and causes carpal tunnel syndrome) Long story short, everything looks horrible if you only look at the bad parts of things. > I feel like people don't know how to use web inspector... You're right, many people don't. I'm not one of them, but I encounter them all the time. That kind of thing is still relatively new, so it's hard to blame them as much as pity them. And of course the Web inspector isn't there outside of a Web browser context. > There will never be native CoffeeScript, you will always debug the JavaScript. I never said there would be native CoffeeScript; I meant they will support source maps for alternative languages. Unless the CoffeeScript compiler is introducing bugs into correct code, being able to get error line numbers in your CoffeeScript file will mean that you mostly won't have to debug the generated JavaScript.
- geraldalewis 15y ago> Verbally Readable !== Quicker Comprehension -> is Coffee-Script's greatest trick. When I first started poking through the codebase, it would take me ages to 'sound out' each line. Coffee-Script is succinct not simply because its syntax is short, but because it is dense. Everything is an `expression`, which means I can be more expressive/loc. I can now read it as fast as any other language, which means I can comprehend code faster. > doSomething() if five and six and seven That was difficult for me to parse as well until I saw it enough. Which is true of everything new I have ever learned. Some syntax took me out of the C comfort zone, and I am better for it. There's a feel that code written "out of order" has that I instinctively like for some scenarios. > Therefore it will never really be supported natively, and will always be a compile-to-JS language, and will therefore always have a terrible debugging experience. Mozilla has been working on this issue in earnest (https://github.com/mozilla/source-map https://github.com/mozilla/source-map). It seems that compile-to-JS languages may be part of some greater strategy. Surely, Google must be working on something similar for Dart. Some progress has been made on the GitHub Issue: https://github.com/jashkenas/coffee-script/issues/558 https://github.com/jashkenas/coffee-script/issues/558
- ryanflorence 15y agoWe scan the left side of the code when reading. Checking the right side of the code to see if it actually will execute must invariably be slower. Also, the language encourages super long comprehensions.
- geraldalewis 15y ago> We scan the left side of the code when reading Exactly. Sometimes you want the predicate muted so the consequence is highlighted. I agree that it seems counterintuitive, but I'm pretty sensitive to code flow and it works for me personally.
- ryanflorence 15y agoconsequence is still on the left edge in my rewrites though, not sure why you'd want to mute control flow aside from reading it out loud. Admittedly, you can still do some ugly one-liners in JS, the undertone of all my points though is that coffeescript's draw is the really beautiful, readable code, which leads to (at least for me) stuff that's harder to follow when I'm not writing it.
- phzbOx 15y agoTo quote the author: "Check out this one-liner I pulled out of the first .coffee file I randomly opened from our application: scores = (student["assignment_#{@assignment.id}"].score for own idx, student of @gradebook.students when student["assignment_#{@assignment.id}"]?.score?) That’s 160 columns of “readable code”..." You can write a 160 columns of unreadable code in any languages. If you guys enjoy coding like that, don't blame coffeescript. You might be right however that it is "more tempting". For instance, with scheme, it's really easy to start using macro and redefining everything; or to nest lambdas into lambdas into lambdas "because you can do it and it avoids using variables". Still, I think it's the programmer's job to write clear code, whatever the language.
- RobertKohr 15y agoThe debugging complexity is more than just a fair point. It is what kills the language for me. I spend way more time debugging code than writing it. I suspect most coders do. Programming has taught me that I am far from perfect. Give me a language where I can jump right to the problem and my debugger will tell me how I goofed up, and I can look at it as a potential language I will use. Give me something where you double my debug time (which will add probably 30% to my total programming time) and I will ignore it. It doesn't matter how pretty and short it makes the code. Give me error line numbers or go home. If you make my debugging more of a chore than it already is, you ain't no friend of mine. I also agree with the author on the need for symbols rather than words in languages. It may make people feel all warm and fuzzy to write what looks like english, but && trumps and every day. {} or () wrapping something gives me a lot of info about what is going on and with little mental parsing. In the end, CS just doesn't deliver a advantage to me that is worth moving away from something as easy to code in as JS, warts and all. And I have tried very hard to want to like it.
- illamint 15y agoI've been working on a large project in CoffeeScript for about 9 months now and have never noticed or felt burdened by the translation between JavaScript source line to CoffeeScript source line in debugging. Maybe it's different for others, but the code is so structurally similar that there shouldn't be a major difference. It's not like looking at the assembler output of a C++ program and having to demangle names and deal with compiler-generated labels and jumps etc.; the structure of the program is still the same, it's just the syntax that's really only mildly different. Of course, though, it comes down to personal preference. Don't want to use CS? Fine! Great! Go hog wild! No one's forcing you to. Me, though? I'll never go back.
- Cushman 15y ago> This is really weird: getUser = (id) -> url = "users/#{id}" dfd = $.ajax url: url format: 'json' method: 'get' url: url promise: dfd.promise() > It’s hard to recognize instantly that I’m actually > calling $.ajax, not just assigning it. If you don’t know > CoffeeScript, I’m sure the last two lines are totally > baffling. Um... I agree, but as someone who does know the language, that's clear, unambiguous and easy to read. I maybe wouldn't use implicit object return there, but it doesn't surprise me to see it. In fact, I'll make a positive argument for the implicit call syntax: the whitespace under 'dfd' tells me, without reading any further, that the line is a call which takes an object argument. Without significant whitespace, I couldn't rule out it being just a typo.
- jrockway 15y agoMy code is more readable for me than yours. That’s just how it is. While the JavaScript CoffeeScript compiles looks decent, it’s still not mine. That would change if you practiced reading other peoples' code. When I see my code, I often think, "yeah, I wrote this" because I know how I name things, but other than that, my code looks like everyone else's code. I know this because I based my style on what other people do, rather than just inventing my own. (At work, people like to write Python likeItsJavaOrSomething, and I refuse to follow that convention. While ugly, it doesn't make the code amazingly hard to read. You get used to it with practice.) Now, compiler output is another thing, but c'mon. Sometimes I have to figure out what the computer is doing by reading memory dumps in gdb or the assembly output of gcc -O3. Complaining about the output of a JavaScript compiler is just silly; do it more and you'll figure it out. Programming is all pattern recognition, and if you can't understand patterns in the output of your toolchain, then you aren't using the tools enough. People also like to complain about things like GHC's type inference errors or Perl's "confess" dumps. I personally have no problem extracting the information I need from them. I write a lot of programs and they fail a lot, so I've gotten good at reading the debug messages. Instead of saying, "this is too hard", try harder, and soon your life will be much better.
- ryanflorence 15y ago> That would change if you practiced reading other peoples' code. I'm really active on github, and actually read the source code of a lot of projects instead of reading books, and contribute to a bunch of them too. Quite assuming of you to assume I don't. My code, since I wrote it, will always be easier to understand because I dealt with every problem--not because of the style.
- sirclueless 15y agoI totally agree with you there. There is something totally different about reviewing someone else's code versus reading your own. Because even if you wrote it a long time ago, it's still easy to reverse-engineer the purpose of everything you did.
- exogen 15y agoA style guide becomes very important in a language like CoffeeScript where (a) there aren't established conventions for the language yet like Python's PEP-8 and (b) excluding unnecessary syntax is very, very tempting. No parens or braces necessary? Don't just omit them everywhere! I was reading the source code for batman.js (written in CS, after having written quite a bit of CS myself), and some lines were absolutely baffling. It took way too much work to parse. I've started building up a personal style guide. The most useful parts for maintaining readability are probably: - Always keep the parens for function calls, possibly excepting oft-used functions that are only being called with one argument. (e.g. document.createElement 'div'; parseFloat '10.5') - Always keep the braces for object literals when used in an expression (e.g. as an argument in a function call); omitting them in a simple assignment is OK.
- latchkey 15y agoIt took me about 3 months of intense CS usage to really get the hang of it. I've written a good 20-30k lines of CS so far for my application, so I've developed a lot of good practices since I started. Now, I can't imagine writing 'pure' JS ever again. I tend to avoid a lot of the one-line comprehensions for the reasons documented in this article (they get difficult to 'parse'). I also tend to write in a more of a Java style, mostly because of my background is in Java. I tend to put (parens) around a lot of function calls so that I can see it is still a function. Sure, CS can be abused to the point of being barely able to read, but that can be said of any language. Having standards and code-review with your co-workers kind of negates that issue. Debugging can be a bit of a pain since you have to find the line number out of a big file. I think this will go away if/when browsers natively support CS. I've gotten good at naming things so that they are easy to search for in the developer tools. That makes finding the right line to put a breakpoint on a lot easier and faster. If need be, I'll throw a console.log('here') in there and search for that too. Context switching between CS and compiled JS takes a bit of getting used to, but it isn't really that big of a deal. I'm already context switching between Java, HTML, CSS, json, etc... what is one more? The fat/thin arrow thing took a while to get used to, but now it makes perfect sense. The change they made (too quietly, imho) in 1.1.3 to not use __bind so much anymore really helped with comprehension. Now I can see the var _this = this in the compiled code and things make more sense to me now. It also helped performance and made me worry less about using it. In most cases, it is safe to just fat arrow things now so it really isn't that big of a deal. In terms of workflow, I found it very important to integrate it in with my IDE so that every time I save a file, all of my CS is immediately compiled to JS. [1] As a result, I don't see any overhead with the compilation phase of things. Being able to declare 'class'es and constructors has also been really great for compartmentalizing my code. Yes, it is possible to emulate all of this in JS, but I find that a lot more difficult to manage. I do wish there was an 'import' statement though. Right now, I hacked that together with the way I'm using LabJS. In the end, is CS a significant improvement over JS? I think so. Just looking at the compiled output of CS, I couldn't imagine myself writing all of that JS code and not making a ton of mistakes (ie: === vs. ==, nesting of brackets, this binding, etc). People say there is a lot of boilerplate in Java... so, when I use CS, I feel that way when I look at the compiled JavaScript. [1] http://stackoverflow.com/questions/6645640/integrating-coffeescript-with-eclipse/7507987#7507987 http://stackoverflow.com/questions/6645640/integrating-coffe...
- PLejeck 15y agoSome languages are designed for professionals to comprehend easily at a glance: these languages use symbols instead of words, use brackets effectively and don't rely too much on whitespace. Other languages are designed to be easy for anyone: these languages use English as inspiration, using whitespace instead of brackets. CoffeeScript has a place, but not in production. It belongs in the classroom, to help those wanting to learn an easy language to program in. Ruby, I believe, belongs there as well. Languages like C, C++, PHP, JS, etc. are all designed for production. They may not be pretty to look at, but they're easy to comprehend at a glance. It's all a question of what learning curve you're aiming for: the learners curve or the advanced curve. TL;DR - tradeoffs: learn them.
- tjholowaychuk 15y ago++ exactly, no one gives a shit how clever or cute your code is, it should be easy to read, all the "noise" people speak of make this simpler. In fact I think that if you have a difficult time parsing it with LL it's most likely a crummy grammar, if parser has ambiguities reading it wont be much fun to read either
- jnbiche 15y agoTaking this argument to its logical conclusion, Perl would be the ultimate language for 'professionals' to use, since it's full of shorthand symbols. And it's true -- if you wrote the code, Perl is very easy to scan. If you didn't write the code, however, Perl is not always so easy to scan. Which is exactly the point of Ruby, Python, Coffeescript, and other similar languages. I´ve heard it said that on average, only 20% of programming is writing original code, and the rest is maintaining other people's code. For this reason, Ruby, Python, and Coffeescript are much easier to maintain for most people than JS, C, Perl, PHP, etc. Personally, I know both JS and Coffeescript well, and have actually done much more work in JS over the years, but the first thing I do now when I get a third-party Javascript program is convert it to Coffeescript (using js2coffee). I can read and understand Coffeescript about twice as fast as I can Javascript, even though I started working with Javascript in 1998.
- PLejeck 15y ago
- andyl 15y agoAll I can say is, I'm way more productive with CoffeeScript than I ever was with JavaScript. Debugging can be a pain. But I'm using Jasmine heavily, and finding that a steady dose of TDD eliminates most of the debugging frustration.
- sunsoong 15y agoThese are all valid points. Debugging is probably the most significant. I agree that the syntax can potentially make CoffeeScript hard to read, but this can be easily avoided. One of the nice thing about CoffeeScript is that it allows one to be selective about the syntax. For example, unlike the author I will use keywords like is, isnt, or, and, yes, no, on, off because I find it easier to read that way. However, I dislike the calling functions without the parentheses and I dislike the long one-line comprehensions. Instead of doing this: eat cheese for cheese in cheeses when cheese is blue I would do: for cheese in cheeses if cheese is blue eat(cheese) I can have a minimal syntax, but retain some of the unnecessary bits to make it easier to read. If the author finds themselves writing code that is hard to read, they should just not write it that way. Write it the way you (and your team) like it to be written.
- rayiner 15y agoThe "symbols are more comprehensible" thing is a bunch of pseudoscientific mumbo-jumbo. Not the least of all because 'and' and '&&' are both obviously symbolic, just with different symbols.
- YmMot 15y agoI think this article is a mix of fair criticisms but at points lapses into a lot of hand waving. At points it devolves into "This is confusing/non-intuitive if you don't know CS" and "This is not the way I like to do things". I find the proposition that porting a library (no matter the size) gives you "as much experience as anyone" pretty dubious. It's clear the author has some experience with CS, and I wouldn't discard out of hand the input of someone who had only used it for 5 minutes...but I found that particular statement a bit dismissive of people who have been using CS for a long time on a lot of different projects. Too often people confuse the "getting comfortable, I basically know whats going on here" phase of learning a language with "knowing" that language...which is really more "I understand this on an intuitive level". I found the "We Process Images and Symbols Faster than Words" section extremely dubious and strikes me as very hand-wavy. I see what the author is going for, but it's a completely false analogy and their point is flawed to begin with. They're trying to compare the acquisition and understanding of new concepts vs the recognition of an already known pattern, entirely different things. Also, the author is essentially cheating, because they are talking about conveying inherently visual information using pictures. Showing someone a picture of a circle and saying "this is a circle" does not convey what a circle is, it conveys what a circle looks like (or perhaps, it does explain what a circle is, but only visually) which is to be sure useful for some purposes. However, it gives them no inherent understanding of how to properly construct a circle, or what it's relation is to other shapes (such as a line) geometrically (say compared to a triangle which could be called any three non-collinear points). With the baby picture, again...I see what they are going for but I think it just doesn't actually support what they are trying to assert. Evoking an emotional response is not the same as passing knowledge, and it doesn't strike me as a good objective to have when writing code. Sure, show someone a picture of a baby and they will have an emotional response. However, they will have no idea who the baby is or why you are showing them the picture which would probably be more useful. All of this does very little to support their assertion that "&&" is somehow more of a symbol and is more visually rich than "and", something I find dubious even disregarding the poor examples. Letters are symbols themselves and "&&" is just as much a "word" as any other, though admittedly more visually distinctive. With syntax highlighting, I would say that there is no objective difference between "&&" and "and". "That is verbally readable code, but it’s not very comprehensible" I'd say that less the fault of CS, and more the fault of the fact that the algorithm they are expressing in it doesn't make any sense: wash plate, brush, sink for plate of dishes when plate.dirty if meal.status is 'done' This is not a valid construct. By using "of" you are iterating through the keys of dishes, which will inevitable be strings. You later check the dirty property of the key (string) which will surely not exist. You need to either use in or less likely, access them as dishes[plate]. (I'd assume dishes in an array, in which case a loop is more idiomatic and safe than for-in) Fine, probably an honest mistake. Sure, I just felt the need to point it out, though I think it does potentially suggest that the author is not yet at the "intuitive" level of knowing CS. You are going to have problems like this in any language where you do not yet fully know it, JavaScript included. Even excepting that, the algorithm doesn't makes sense. You're cleaning your sink and brush after washing each plate? Doesn't make much sense. I suggest a more realistic version: if meal.status is done wash plate for plate in dishes when plate.dirty wash brush, sink The author makes a couple points about their original comprehension; how it's densely packed, and I think this largely untangles them. It puts the most important predicate first. You don't need to know immediately that you are dealing with the dishes array... The code is composed of discrete "pieces" and each depends on the others. I think it's arbitrary to say "oh I need to know I'm iterating through dishes first thing". It's just as useful to say "ok, I'm going to be washing something, a plate...". That provides a context for everything else. The fact that it's a comprehension is pretty obvious immediately so it's just a case of deconstructing it. So overall I find this a bit of a straw man. It doesn't make sense to begin with, it doesn't need to be so packed, and it's taken out of context which dramatically cuts back readability. If you were writing an app about doing things in the kitchen, the comprehension (even the dense version) would make quite a bit of sense because the context would make certain things more obvious. In my code, this section would probably be prefaced with a comment like: # cleanup wash dishes wipe counter stow utensils So the fact that we just spent X number of lines getting dishes dirty, and knowing precisely what a dish object is in the context of the overall program i.e. that they need to be cleaned, it would be obvious that I need to now wash them each in turn...amongst other things. Now really, I see what the author is going for. List comprehensions get messy fast. Sure, I just don't see this as a criticism of CS per se and I find the example poor. Remember, just because CS offers extreme conciseness doesn't necessarily mean you have to use it. I'll admit CS users often make a big deal about conciseness, and that can send mixed messages...but I would say in most cases it's about demonstrating that power is there if you need it than saying this is always best practice. The author clearly understand this as they go on to provide more readable examples, but it bears repeating. I could similarly break down the "one liner", but I'm running pretty long already and don't have forever. Again, what is probably a misuse of "of", and sticking more than is needed in the comprehension. I get the idea that the point is you can do this, but every language has powerful features with which to shoot yourself in your foot. If the author actually found that in their company's code, I most respectfully suggest perhaps they don't know CS well enough or it may not be their style. At any rate, it would explain their distaste for CS. "It’s hard to recognize instantly that I’m actually calling $.ajax" I suppose, but CS uses juxtaposition to call functions, if you see identifier\wvalue or identifier\widentifier...it's a function call. I would say, remember CS's golden rule: when in doubt disambiguate. Feel free to add () to function calls. I think the next point the author makes it better. I would say that it's just an unfortunate fact that in many languages some constructs will be ambiguous. I think CS does a good job of pushing ambiguity to edge/rare cases. In the author's particular example I would note the point is a bit moot because CS has implicit return: getUser = (id) -> url = "users/#{id}" dfd = $.ajax url: url format: 'json' method: 'post' # return url: url promise: dfd.promise() In other cases I would refer you to the Golden Rule. "Now with the fat-arrow, people are encouraged to fat-arrow their way to oblivion" I find this a dubious assertion. Stupid people maybe, but I doubt very much giving stupid people JavaScript will give you overall less problems...just different ones. At any rate, I don't see any problem with saying a tool should be reserved for experienced users. "Therefore it will never really be supported natively, and will always be a compile-to-JS language, and will therefore always have a terrible debugging experience." I disagree. The browsers are working on features to make such debugging much easier. Further, I know a few people working on CS in CS interpreters, so that if you need a richer debugging experience you could run your scripts through the interpreter rather than as JS. Granted it will probably never be as rich as the Developer tools in the browser, but between the two I would say it's enough. The author noted they feel the need to throw in a lot of logging in to debug. I would say this is a style a lot of CS developers I know use, myself included. I am quite adept with the developer tools, having debugged JS since the Venkman and Visual Studio days, but I just don't feel the need for that sort of debugging very often. For me, it's either a syntax error or a problem with the flow of data through my program. The only time I really break out the debugger is debugging other people's code. Editor macros make inserting logs dead simple. A good build process removes them except when needed. I can appreciate that some people will find this workflow annoying and a pain, which is fair. I just want to note I find it works superior for me. So this is getting long. Despite my objections, I like this article. CS is not perfect by any stretch, and it's still relatively new. It needs work. It needs criticism from the trenches. I think most of the stuff in this article is mostly fair. However, I find that CS suits a particular group of developers...and for them it is a very useful tool. I think that a lot of people criticize it without realizing that really they don't fit into that group.
- cpher 15y agoWhat are your experiences writing CS on top of another well-established javascript API framework, e.g. Dojo. I do a lot of work with ArcGIS Server's Javascript API, which is based in Dojo. I also mix in Jquery when needed (because I prefer it over Dojo). So, would CS be a benefit in these situations, or just muddy the waters?
- ryanflorence 15y agoIt's totally natural. So if you prefer CS don't let using a third-party lib change your mind.
- sharjeel 15y agoSeems like author is trying to learn a new language and is having a hard time getting out of the shell he created around him with experience. During the struggle he wrote this post. I had exactly same feelings about one-liners and understanding succint statements when I was learning Python after years of programming in C.
- dreamdu5t 15y agoJavaScript looks better than CoffeeScript...
- samgro 15y agoI just spent my entire day tracking down a missing "var" that caused a bug only in Internet Explorer. I haven't written any assembly code since college, and I hope to reach a day when I never have to write or maintain native Javascript again.
- zackattack 15y agoYou can set up your IDE to automatically run your code through JSLint or JSHint, which will detect such errors.
- pacomerh 15y agoAlso, talking so much about using it or not adds another layer of complexity :)
- dmauro 15y agoThe debugging problem is definitely the biggest strike against CS, so it's weird that most of the article focuses on stylistic options (all those parens, brackets, and ampersands are optional!). I'm still feeling CS out in terms of what style works best for me (for instance: should I always wrap arguments in parens so that all function calls have parens following them?) but it's nice to have that flexibility and be able to find what I think is readable and clean. For instance, I prefer '==' because it parses better at a glance, but I find that 'is' is much faster for me to type. :/ Also the white-space argument meaning it will always be compiled is not necessarily true. CS's brevity over JS would probably make up for the significant whitespace difference.
- antirez 15y agoI agree with the author of this post. What is interesting for me is how people are happy to use an intermediate layer in front of javascript just to gain some syntax and not real semantics. CoffeeScript does not really change the complexity of your program. I agree that in modern languages it is a good idea to avoid all this parens and useless syntax that we have in Javascript, ObjectiveC, and so forth, and I hope next versions of Javascript could even change syntax at some point, but to use an intermediate layer/compiler/translation stuff just for that... is strange.
- chc 15y agoThere are real semantic differences in CoffeeScript. As listed by jashkenas himself more than a year ago in response to the same accusation: Leaving features off the table and just talking about semantic cleanups, here's a few: * Switch statement doesn't fall-through by default. * Variables don't need to be declared with "var", and can't ever become global accidentally. * Equality is strict, using `===`, if you want coercive equality, you coerce the object yourself. * Loops that are used to generate functions close over their index variables, so that all inner functions don't share the final value of the index. This is the same problem that ECMAScript Harmony introduces "let" to solve. * Splats largely replace use of the "arguments" object, so you don't get bit by "arguments" only being a faux-array. * Comparisons can be chained, as in Python -- so you can write: "100 > x > 25", and have the answer be correct. * Multiline strings are valid without having to escape the newline. * And the big one: everything in CoffeeScript is an expression. Without having to use temporary variables, you can return the result of an if/else from a function, pass a comprehension (loop) directly into a function call, assign the result of a try/catch, and so on. (http://news.ycombinator.com/item?id=1697586 http://news.ycombinator.com/item?id=1697586)
- antirez 15y agoThat's definitely more semantics that I thought it contained, thanks for the clarification. However for the same reasons the debugging problems are probably more severe than I realized before.
- 15y ago
- johnx123-up 15y agoNote: This page is crashing my Chrome
- ms123 15y agoAm I the only one to completely disagree with the author? It's important not to mix everything. CoffeeScript is a language. There just happen to have an implementation for it. This invalidates the "debug" workflow problem. Let me restate the CS debugging workflow: Start discovering the problem in the code I wrote. Fix it in the CS Problem fixed, move on, otherwise start over. A computer language is by definition a mean to express unambiguous statements. So does CS. So does the other languages. The resulting program will do exactly what your code asked to. Do we check compiled code when we code in C? Do we look at the Bytecode when we write Java? The fact that CS compiles to JS is an "implementation detail". That's the CS compiler's job. If you don't trust it, don't use it.
- skeptical 15y agoIt's the only implementation almost everybody knows of. I've never heard of any other, don't know if there is other. In defense of the author, he does explain why it will most likely always be a language that will be implemented in a compile-to-js fashion. Do we check compiled code when we code in C? Do we look at the Bytecode when we write Java? This is exactly what he is complaining about. Also, he does makes a few points about CS syntax, that can't be the implementation's fault.
- dextorious 15y agoYou take the "useless pedantic comment of the year" award. Yeah, "it's a language". In bloody THEORY. In reality it's also ONE, and only ONE, specific implementation widely used. In reality the language IS the compiler. And that implementation compiles to JS, not as an implementation detail but as it's sole reason to exist.
- ms123 15y agoThanks for the award. Yup, there's only one implementation. But doesn't in change? What will the compiled code be like in 3 years from now? The compiled code's prupose is to be optimised, not consistent. This is my point. By restricting yourself to think Javascript when you're coding in CoffeeScript, you're producing a code that sucks in JS and in CS.
- ricardobeat 15y agoAs a year-long CoffeeScript user, I have a few points to rebut: debugging workflow: he makes a long list of bullet points, when in practice you can find the error directly in your coffeescript code 90% of the time, since you have a clear image of what it's compiling to and errors tend to happen on the piece you're working on. Hopefully source-mapping in Firebug/Inspector will be ready in a few months and end this discussion. "We Process Images and Symbols Faster than Words": It has been demonstrated that the understanding of text is based on the same principle, we don't "read" words, we identify them. and and or are as much a symbol as == and && (which you still can use if you think they are more visible). "ugly syntax": the examples are ugly. Don't use a trailing if for long conditions, don't create huge one-line comprehensions. You can do worse in javascript. if five and six and seven doSomething() "bad parts": every language has bad parts, but the example is just bad practice. Just because you can omit return and start an object literal without indentation doesn't mean you should. getUser = (id) -> dfd = $.ajax url: "users/#{id}" format: 'json' method: 'get' return { url: url promise: dfd.promise() } "Significant White-space Means CoffeeScript Will Always Be Compiled": what? No it doesn't. You can compress coffeescript, you can't minify it. Readability is not a strength of most javascript code out there.
- ricardobeat 15y agoComments are welcome.
- iambot 15y agoThat was a brilliant article, the most complete honesty about coffeescript that actually makes sense. After reading it I really felt like coffeescript is cool. but you know what he's got something there. he really does => I'm going to stick to JavaScript ("See what I did there"). thanks;
- kristopolous 15y agowhat about these reasons: 1. It's trendy. Snooty programmers use them. 2. It's hyped. Annoying masters of hyperbole won't shutup about it. 3. javascript is already easy to write, easy to read, easy to use, and well understood. But really it's because I despise hype at such a deep and fundamental level; it leads people to being impulsive and emotional; making decisions based on personal reasons rather than finding the right tool fo the job. countless times i've seen people work significantly longer and harder with the hype technology then if they had just been solid project managers and made good decisions regardless of what is being currently blogged about. other times i've had legacy systems that were built in the super-trendy tech of yesteryear that was a fly-by-night and nobody uses any more ... sometimes you will have managers for instance, that wlil request something like perl code to be rewritten in ruby or some other rearranging of the deck chairs kind of activity. It's a complete and utter waste of time. I'd rather go home and click on all those nsfw tags ... so yeah, no freakin' way; unless there is native support, it's been around for a few years, and there is actual real solid evidence that it doesn't suck (extra time that is) for a similar goal.
- roestava 15y agoIn other words, you find it more advantageous to be a late adopter, which is fine as well. Letting the market to select the tools you'll be using seems like a standard approach to most people. Early adopters can be such trouble makers. All tools bring tradeoffs with them and many times early adopters don't anticipate them all.
- MatthewPhillips 15y agoMy biggest problem is that because it lacks firm rules in a lot of area, CoffeeScript is a language that is not always intuitive. With JavaScript it's pretty simple to know the rules; they are completely uniform. Not so with CoffeeScript. Here's my biggest gripe: greet = (greeting, person) -> "#{greeting} #{person}!" greet "Hello", "world" That's simple. A function that takes 2 parameters, separated by a comma. But wait, here's another: longRunning = (onsuccess, onerror) -> dosomething (e) -> if not e.error? onsuccess() else onerror() And the implementation: longRunning () -> "Yippee!" () -> "Oh noes" A function with 2 parameters, this time separated by a carriage return, not commas. How would one know that intuitively? That some times functions parameters are separated by commas and some times by carriage returns? Or that some times function calls have to include the () (when they have no parameters) and some times they don't (when they do have parameters)? I'm sure these things become second nature over time, but learning them will result in a lot of trips to StackOverflow as you wonder why your code doesn't behave as expected.
- jashkenas 15y agoOne wouldn't know that intuitively, because what you wrote: longRunning () -> "Yippee!" () -> "Oh noes" ... is not valid CoffeeScript. I'm not sure where you got that from. Ideally, you'd write it: longRunning onSuccess, onError Or, if you really wanted to use two inline functions instead of local variables: longRunning (-> "Yippee!"), (-> "Oh noes")
- MatthewPhillips 15y agoThanks. A more realistic example would, I suppose, look like this: longRunning (-> ### bunch of stuff happening for success ### ), (-> ### bunch of stuff happening for failures ### )
- jashkenas 15y agoYes, that'll work fine, as will this, if you prefer: longRunning -> # bunch of stuff happening for success , -> # bunch of stuff happening for failures
- jashkenas 15y agoThere has always been a strong "case against using CoffeeScript", from day one. Like any other new language, it's a new, strange thing to learn, there's new tools and a new compiler, and your team doesn't already know it. In addition, CoffeeScript has it's own distinct burden to bear: the entire point is to compile (in as straightforward a fashion as we can manage) into JavaScript. That you're debugging JavaScript when you run CoffeeScript in production should be no surprise -- that's the point. But it's also quite a large hurdle to jump. What's interesting about CoffeeScript is that despite there being a strong case against using it -- and I try to make the same case in my workplace -- people still find it useful enough, and transparent enough, to use it regardless. As of this morning, CoffeeScript is the 13th most popular language on GitHub, and the second most popular module in npm, after Underscore. All of the top ten languages on GitHub date from the mid-1990s or earlier. https://github.com/languages/ https://github.com/languages/ http://search.npmjs.org/ http://search.npmjs.org/ The better question is not "What is the case against using CoffeeScript?" ... but instead: How is it that despite all of the obvious hurdles stacked against a new source-to-source language, people are actually using CoffeeScript? That's the question I'd like to know the answer to.
- danmaz74 15y agoIn my case, Rails 3.1 is the answer. I never felt the urgency of a better JS so much as to look for solutions, but having it already integrated into the workflow makes you really appreciate it. Except when debugging, of course :)
- roestava 15y agoWith JavaScript ordinary developers hit a wall at some point and can't make further progress. Like Java has shown, how good the language is seems secondary to how good the implementation, the runtime, is. JavaScript runtimes have kept on improving and with the V8/Node.JS combination have started taking over the server-side code. With careful engineering, developers can get even further with just JavaScript the language. I wonder for instance whether using the Google Closure Tools can bring more gains there. Such tools help with checking the code for common pitfalls and the style guidelines also help a bunch. Plus, they might help with deployment, with the packaging for the specific program you've written so you don't need to package up all the library with it. Then you don't need to feel ashamed of making use of lots of library code, if only the part of it that you're using gets deployed. Still, working with JavaScript directly can also bring debugging challenges, even more when you're trying to debug code that has been mangled since leaving your library source files. Languages like CoffeeScript and Dart have success because the alternative in pure JavaScript is still quite painful, as I've mentioned above. It's a mistake to dismiss languages like CoffeeScript and Dart because you want that 50% extra performance. Still, CoffeeScript is a concept. It could be said to have been over-engineered in places. Some of the stewards of JavaScript would have found it better if it was more like a JavaScript with JSLint turned on and some niceties on top of it.
- ghc 15y agoPythonista and Haskell hacker here. Everything he hates about Coffeescript is what I love about it, minus debugging. My debugging workflow looks entirely different (and more efficient) than his, however. While I can't say for sure, it reminds me of the days where Java programmers would try Python and complain that it was harder to write Java code in Python than it was in Java (esp. with getters and setters).
- phren0logy 15y agoCan you please give some details about your debugging workflow? I'd love to know what works well, as I've been a bit nervous about making the leap to CoffeeScript for more than just goofing around for this reason. I write a little Python, but I'm not great with JavaScript, and this seems like a barrier.
- peter_l_downs 15y ago> You feel pictures and symbols, you feel the relationship. > one !== two > isSet || isDefault > > one isnt two > isSet or isDefault I agree, but it's important to note that pictures and symbols are only felt because the relationships have been so well defined in the past. I'm not a JS or CoffeeScript developer (I use python and C mostly), so "!==" is much less clear than "isn't".
- Andi 15y agoI use CoffeeScript in nearly all my JS packages now, and I like it a lot. But I do not like how many people use it. I use only a subset of the features. The most important aspects are: short function syntax, implicit vars, short object syntax, function binding to this, @. I always use brackets when calling functions, because you need to use them anyway, when you do not pass any arguments. Omitting brackets makes CS nearly unreadable. CoffeeScript is a big win for whatever I am doing. The resulting JavaScript is more stable since CS removes the possibility of a lot of flaws and giving developers the best parts of JS. On the other hand, you still need clear and constraining guidelines to manage complex projects. But you need that in any language and framework. It's not just a necessity in JS development. Thank you, Jeremy. It pays off!
- ccanassa 15y agoCoffeScript just adds more complexity into a already complex problem.