Eh. I think it's pretty silly. It basically boils down to "If you write terrible Coffeescript, it's hard to read". Duh?
Any time you are writing code that is ambiguous, use what you need to in order to clarify it. Don't omit punctuation just because you can if it makes the code less readable.
action(true,
option1: 1
option2: 2
)
Using empty parameters in a function declaration is even funnier; you're adding punctuation that makes the code more vague. Just omit it!
doSomething -> 'hello'
doSomething(-> 'hello')
The third example is totally valid, and one I completely agree with - omitting parentheses on inner nested function calls makes for unreadable code. Don't do it.
The fourth example - complaining that inconsistent indentation produces inconsistent results - is just incomprehensible to me. When you're using a whitespace-delimited language, you'd best pay attention to your whitespace.
Ambiguities with optional curly braces are certainly nothing new to Ruby developers. Convention is that only the last hash in an argument list may have its braces omitted (or more stringently, a hash may only have its braces omitted if it is the last parameter in the list). Makes for finely readable code. Don't write unreadable code.
One of the fundamental rules you should follow when working in any language is "don't be clever". Optional parentheses can make for very clean code, but if you try to get "clever" with them, you end up with ambiguous code. List comprehensions are awesome but if you use them when there's a simpler construct you can use, you're doing it wrong.
You can write bad, unreadable code in any language. Part of maturation as a developer is learning to write readable code, not just working code. A bad workman blames his tools.
No, sorry, omitting parentheses (because they're optional) can be "too clever". I love optional parentheses, but I feel like a lot of people omit them because they feel that they're supposed to, at the cost of code clarity. I'm arguing that you should omit them when doing so doesn't make the code ambiguous, but if you ever need them to improve code clarity, that you should use them.
The OP had a fine example of "doing it wrong", with the nested inner function call without parentheses. While technically valid, it's bad code because it's difficult to read, even for someone accustomed to optional parentheses. Such a construct is "clever" when it shouldn't be.
But then you have to think everytime whether you should put parantheses there or not. Is the code readable without parantheses? Should I put them there in case someone reads the code in a year and doesn't know about the problem domain ... ? It is not much, but it is extra cognitive load that is wasted.
It's akin to programming C and everytime you write a function, if statement or for loop you have to ponder whether it looks best to put the opening brace below the line or at the end of it. I hate reading code with an inconsistent brace placement style like that.
If writing good, maintainable code requires knowing/using a large number of rules and best practices that aren't part of the language (and whose absence are actually considered to be a virtue of the language), that seems like a flaw in the language itself.
Yes, you can write bad code in any language. That doesn't mean that languages don't have an impact on the ease of writing good and correct code.
If you think that the existence of style guides are a flaw in their respective languages, then I'm going to (as non-condescendingly as I can via text) suggest that you may not be a very mature developer yet.
Style guides and best practices exist for every commonly used language, and not because of flaws in the languages themselves, but because unless there is literally only one way to do things, a dozen developers will come up with a dozen ways of solving a problem.
There's a difference between style guides offering a well-lit path to follow, and a language having a large number of possible expressions that are off limits in practice because they lead to bad code. The former marks out a path, the latter indicates a minefield. When the language's design actually facilitates the creation of bad code, not just by offering the possibility of dangerously ambiguous expressions, but by touting that possibility as a plus, that's a flaw.
Maybe accepting that flaw is worth it because the expressiveness of the language makes it a net plus; doesn't mean it's not a weakness or flaw or a point to be cautious about.
I do apologize - I didn't mean to be perjorative. I meant to communicate that I've heard the sentiment ("why does it let me shoot myself in the foot? It shouldn't let me do that!") espoused by many, many new developers, and it's an attitude that I've seen many people grow out of.
Coffeescript is a very flexible language. Its flexibility lets you do bad things with it, but the flipside of that attribute is that you can do very good things with it. I don't think that it's either "a path or a minefield"; I think those are two sides of the same coin. Optional parentheses and whitespace delimiting can reduce visual clutter, but if you abuse them and reduce it too far, you increase cognitive load on the person that has to read and maintain the code.
The more stringent the language, the less guidance you need in the form of style guides and community standards, but that's simply because the language itself imposes those standards on you as a byproduct of disallowing flexibility. It's absolutely something to be cautious about, but it doesn't make the language inherently flawed.
Syntax flexibility is not a virtue. Creating restrictive rules about what I can do to an object or how functions work ties my hands when I try to do tricky things, but syntax only limits my artistic urges to do esoteric code layout.
The C style syntax situation with optional if brackets is almost universally considered a flaw:
if (foo)
st1();
st2();
This is not the flexibility to do hard things. It does not save a lot of typing or make some other common construct less cluttered. It is just a defect in the grammar that it's too late to fix.
It sounds like Coffeescript has more of these flaws.
I don't consider the optional braces in C-if a flaw. I use them for early return often, eg
if (somethingBad)
return NULL;
restOfBody();
And I find that the braces are often just unnecessary visual noise. Of course, there is always the issue of people adding extra statements, but I haven't found that to be a problem in practice. YMMV though
The trick to avoiding the problem of extra statements is to only skip the braces if it all fits on one line:
if (somethingBad) return NULL;
That's a clear visual indicator that the braces have been skipped, but it's basically impossible to look at the next line and not know that it's NOT part of the conditional. Also, if you're having trouble fitting it all on one line, it's a good cue that you're not in a situation where skipping the braces is safe.
I think there ought to be a distinction between semantic flexibility and syntactic flexibility, though. They may be correlated but it's not always clear cut. Lisp is an example of a syntactically inflexible (s-expressions or walk) but semantically rich language (macros).
My own opinion is that syntactic flexibility does have value (e.g. Haskell). I think it's also vastly overrated relative to that value; syntax is incredibly easy to bikeshed. Semantics require you to know something about the languages at issue.
That said, my opinion is that this kind of syntactic flexibility offers dubious value if the trade-off includes not just obviously broken programs but also subtly broken ones with errors which are difficult to spot. Newbie errors are part of the learning curve, but these seem like mistakes even experienced people can make.
> Its flexibility lets you do bad things with it, but the flipside of that attribute is that you can do very good things with it.
The problem is that there is a local maxima in the flexibility cost-benefit curve. After you reach that maxima additional flexibility degrades your experience.
But surely for a language that is almost purely designed to make syntactic improvements, the designer could have taken a stronger stance on syntax. I wish he could have at least decided on semicolons. The beauty of Python is that it is actually hard to write unclear code that does what you think it does. I'd love to see a PEP-8 for CoffeeScript or some kind fo built in linter.
Not saying that they don't exist, but I've literally never seen a python style guide (other than "don't mix tabs and spaces", which is part of the language now), never seen someone make a commit just to fix code formatting in python (something that happens quite often with every other language I use professionally), and never had any trouble working on other people's python.
I agree with you in theory, but in practice when working on large teams, languages as flexible as CoffeeScript do become a problem. That's a major reason languages like Java and even C# are so inflexible.
For my personal projects or small teams I'd have no reservations using CoffeeScript if it felt like the best fit. For large teams, I'd reconsider.
> "If you write terrible Coffeescript, it's hard to read"
No, it's "If a language that provides for many ways to write terrible code (incl many ways to write the same code), people will write hard to read code." For example if parens are required, it is impossible to "get clever" with not using them.
> No, it's "If a language that provides for many ways to write terrible code (incl many ways to write the same code), people will write hard to read code."
A prime historical example being Perl. A second one being PHP.
I have recently implemented to quite large project with CoffeeScript, the most recent one for a full export to HTML for http://flairbuilder.com, and I have to say that CoffeeScript is a superb language. It's a pleasure to work with.
The kind of problems that the article points out are easy to spot. If small syntax changes yield significant output code, that will be immediately reflect in the program execution.
Plus, a decent code base will have unit testing in place, which should catch more intricate, harder to catch, unwanted code flavors.
> The kind of problems that the article points out are easy to spot. If small syntax changes yield significant output code, that will be immediately reflect in the program execution.
> Plus, a decent code base will have unit testing in place, which should catch more intricate, harder to catch, unwanted code flavors.
Look at it this way. Is it easier in general to read JavaScript on a large project over time or CoffeeScript? Sure, with either one there are things that could be annoying, just like with any language, but overall I would want to rely more on CoffeeScript than JavaScript. The reason being that for junior developers and other people that contribute to your codebase, CoffeeScript forces them to adhere to certain conventions that normal JavaScript does not have. Sure, if you have a great team that does everything perfect, well formed JavaScript can be easier to read and maintain, but that is not the normal case.
Seems like there are two types of developers: those who don't want even to hear about CoffeeScript and trying hard to find deficiencies in it and those who embraced it and feel unhappy every time they are forced to work with vanilla javascript again.
Extremists are generally the noisiest. I use CS in a Rails project along side JS without a problem. It's not a massive web site but I haven't hit any big snags mixing the two.
Most of the bad code examples in this post are taken from the CoffeeScript compiler itself. For that I have to say "mea culpa". There's a lot of overly clever and dense bits that have accrued in the compiler over time -- sometimes due to the tangly nature of the codebase, but also sometimes because we tend to use the self-hosted compiler as a test bed for edge cases of combining different language features together.
If you're looking for more regular style, this style guide is a better place to start:
I was literally coming here to post this response. It seems like a revolution in (usage of) coffeescript is needed in much the same way Crockford's Good Parts paved the way for writing good javascript.
Note: I'm not saying Crockford was singularly responsible for this, but The Good Parts was certainly well-received and very much popularised for it's opinionated views on the language.
Edit: I mean in terms of coding style, CS itself has already cut out a lot of The Bad Parts of JS
I myself enjoy using CoffeeScript, but I understand it might not be for everyone.
It's always good to look at the pro/cons before choosing a language, so I think discussions like this is good.
That being said, some of the problems this article points out can be addressed by going back to more JS style.
e.g. Not relying on implicit parentheses/commas/braces
I like the "Fancy" for loop because it's closer to what I do in Python (yes I know they are not exactly the same). Same thing with the "Tricky" if statements.
Also the redefinition shortcuts provided in CoffeeScript is pretty much what I do in plain JS anyway.
I agree, it is too bad that CS has so many optional ways of doing things. That said, it is possible to write unreadable code in pretty much any language. If you have a good style guide and stick to it, it is easy to avoid all of these issues.
I don't consider this article bad at all, because it really makes some good points.
However a lot of criticism seems to come from the fact that the author is a Python programmer and therefor wants CoffeeScript to be more like Python. No, I am not saying something like the author not understanding it isn't meant to be Python, but for example the implicit vs explicit debate is certainly a more philosophical view. Ask people who prefer other programming languages and they will have a different view. Hey, after all that's why there are so many, even if Ruby, Perl, Python, Falcon, etc. have very similar use cases.
My opinion for example is that dynamic languages are very implicit in first place so saying you don't want that (at all) doesn't make too much sense. I also don't have problems reading CoffeeScript, but occasionally had problems with very explicit languages being too verbose which can make it harder to follow. So looks like my mind works slightly different here.
But back to the article. There are lots of valid points. I think coding guidelines, which one should have working in a team, no matter what language could solve some of them. Some points look a bit like mixing different styles on purpose and at least can't see how you could find something like that in the wild. Just because you can code ugly, it doesn't mean you have to, but again that is more of an opinion. Some people like usually verbose languages, because they say they are easier to read, others like ones with shortcuts or where you have multiple options to express things, making it easier to read (for some people). I for example always enjoyed the fact that Perl has unless and until in place of negated if/while.
But that's more what you prefer. But hey, CoffeeScript is all Javascript, so if your team doesn't like it it's (comparatively) easy to step by step switch back.
It's funny, because as a big fan of Python who has had to do a lot of CoffeeScript lately, I find CoffeeScript very similar to Python, and very readable. It's certainly more readable than JavaScript, when you don't get fancy. It's called "Unfancy JavaScript" for a reason.
Many of the issues raised in this article can be solved by "simply" not doing it (admittedly not always a real solution). Just because the language allows something to be done, doesn't mean it should be done that way. Our team has a styleguide that clearly explains good and bad practice, for CoffeeScript AND Python. (It's possible to do bonkers stuff in Python, too, just harder.) It includes things like: use explicit returns, especially when intending to return nothing; include parenthesis unless it's more clear without them (callback as arguments).
Yes, it'd be great if the language were more explicit and made it harder to do confusing thing. But, its core goal is being "just javascript", which prevents some of that explicitness. Also, the flexibility lets the real goal be clarity.
because it doesn't have all the crap. CoffeeScript's whitespace syntax is even more helpful when those objects start getting nested. Plus, not having to deal with trailing commas is amazing. At the same time,
I try to not be "that guy" when it comes to CoffeeScript, but it's easily one of my favorite languages now. All the crap that JavaScript requires is just gone.
I do every day, both in CoffeeScript and in Python. I find things like braces frustrating, because I already keep it indented, and have to then manage the openings and closings. With proper 'aesthetics', indentation is perfectly readable. Plus, if something starts getting too indented than is readable, it's a sign that it needs to be refactored. (Whereas JavaScript looks messy even with otherwise sensible nesting.)
Sorry, CS and Python treat whitespace as a significantly different beasts. It's a disservice to everyone to say, "I read <insert significant-whitespace-block language> everyday, therefore <insert language that substitutes anything from call points, to auto-insert this or that, infer types, etc> is just fine!"
I think a majority can grok and parse Python, but the same can certainly not be said for CS. It's unfortunate too, because it has some Good Parts.
I didn't mean to say "Python does it, so CoffeeScript is not a problem", but rather that both can suffer from too much indentation. CoffeeScript is a little more prone, given the callback-heavy nature of JavaScript, but similar treatment of surrounding whitespace is helpful in maintaining clarity. (Basic example: I find Python's standard of four-space indentation helps CoffeeScript readability, and prefer it over the popular two-space indentation.) And in both cases, excessive indentation is a useful signal.
Readability is very subjective and depends on the user's knowledge of the language, as well as personal style, or 'accent', if you will. Code written with, for example, leading commas in dictionaries instead of trailing commas just looks bizarre to me and is a little harder to read, to me, even though I like to do something similar and stack colons.
yeah python is still much clearer than coffee. I used to somewhat prefer significant whitespace but coffee has definitely killed that for me haha. Seeing braces after looking at files of coffee is like a breathe of fresh air, it just lines up nicely for the eyes, even from an "artistic" stand-point I think the balance is more appealing
But far better, if you have any say in it, is making the callback the final argument to someFn.
someFn arg1, arg2, arg3, -> doStuffInACallback()
The thing about coffeescript is that most of the pitfalls being discussed here are very easily avoided with a modicum of experience and sense, whereas in javascript, many of the core issues simply cannot be avoided, and must be worked around in plainly ugly and bug prone ways (see: string concatenation, this/that juggling, "])})]));, just for starters).
I've been using coffeescript for about two years - I thought it was the best way to keep the pleasant aesthetic of python, which was my favorite language, and have been happy working with it ever since.
I just want to throw out a positive experience with it and to say that I don't support the author's premise of "here's some misleading things you can do with CS, therefore CS is unreadable". This applies to all languages, and 'fanciful' features and syntax should be avoided almost always in every language for the sake of readability.
There are MANY reasons not to use coffeescript, but JS is all functions all the time, and -> is my best friend.
That is a good example, and something that is eased by syntax highlighting (although I rarely implement double-bar function literals, keeping a pythonic 'self = this' reference is preferrable in most cases)
Although it is all subjective aesthetics, CS shines when paired with underscore.js, and really all "callback-as-last-argument" paradigms, ie:
_.each items, (item) ->
# do stuff with item
# ...
while the points in the article make sense and I agree, if you keep your Coffeescript code consistent I really don't suffer a readability problem, especially relative to JS where there's like 5x more code to go through
well, personally when i converted over i never had to stare at these blocks anymore:
}
}
}
});
made code a lot easier to debug.
and yes, consistency wasn't the only thing. i would say that converting over has a learning curve sure reading other people's code. but sacrificing readability long term compared to vanilla js? i wouldn't say that. i'm not saying there isn't ambiguity in the beginning but eventually you learn how to not do things in ambiguous ways.
The moment you try to do simple things like concatenating a string you realise that javascript is a bit more tedious than it needs to be.
While nowadays I prefer coffeescript to js, I would rather have some syntactic sugar like scss is for css. I've looked into it but nothing has enough momentum to make me sure it will still be around in two years or so.
As a sidenote, while I mentioned I prefer CS, have you ever tried using a ternary operator? or pass a callback function in jquery (ex. the hover out event)? or just return "this".
There are so many things that feel so wrong.
Feel so wrong in... CoffeeScript? Or JavaScript? I think ternaries and callbacks are both much cleaner in CS (with the exception of "callback, something-else" which does end up a little funky unless you add parens). Just naming a variable to return it seems a little wrong to me but you can always leave the "return" in. "Optional" is very different than "never use".
Don't get me wrong, I love the fact that I can do nice stuff such as callback?() and some other nifty tricks, but while I'm still having fun using coffeescript, in my experience it's not that great as most people make it up to be.
I prefer words to symbols any day. I think coffee's ternary is better. Also, I have no problem throwing singular @s around cuz they're short and get used so often, but typing out 'this' would be fine too.
Personally, i write my CoffeeScript with as much syntax as possible, to keep it as readable as possible: as a rule, I always use parenthesis and commas while leveraging CoffeeScript's "good parts".
But that said, the last couple of projects I've written in pure JavaScript and it's actually made things much easier to go back and read. Like the author of this post, I too have had difficulty reading back over my old code and, at a glance, understanding precisely what's going on.
Over the past couple of months I've gone from being absolutely devoted to CoffeeScript to on the fence, mostly due to readability.
(I'd love to see a fork of CoffeeScript that forces syntax.)
I haven't programmed in Coffeescript, but does it bother anyone else that new variables are introduced without "var"?
When reading js, seeing the "var" really helps me to know the programmer's intent that this is a new variable being introduced, not an attempt to reassign one that should already exist. Does CS have features that make this point mute?
> I haven't programmed in Coffeescript, but does it bother anyone else that new variables are introduced without "var"?
Yes. I've come to see it as a mistake in Python and Ruby both, and I'm definitely not pleased by its usage in CS. Even less so as it uses the same rules as Ruby's lambdas without the stops of its methods and global scopes.
Actually I think this is a big plus, as it's much more common to want to declare a new variable than to want to reassign a global, and hard to notice when something is missing like "var". It would be nice if there was an explicitly different operator for reassignment. (p.s. I think you mean "moot")
This doesn't bother me at all. Mostly because this feature comes from Ruby and so I'm already used to it, but also because it takes away the nasty surprise that JavaScript gives you if you leave 'var' out. I find this invaluable. As for knowing whether or not a new variable is being declared, well, that's why you keep your functions (and therefore your scopes) short.
> This doesn't bother me at all. Mostly because this feature comes from Ruby and so I'm already used to it
This and that are completely orthogonal though, I've been using Python for 8 years and Ruby for 6 so I'm used to implicit scoping. Doesn't mean I like it, or find it a good idea to use it in new languages (I don't).
And the issue is actually bigger in coffeescript than in ruby and python both, interestingly because (through javascript) coffeescript's scoping is much more regular than Python's or Ruby's.
The only language in which I don't know implicit scoping to be an issue is Erlang, because it uses bind-once and immutable structure semantics.
> also because it takes away the nasty surprise that JavaScript gives you if you leave 'var' out.
That can trivially be fixed by linting, or using strict mode. That's really no argument.
A few years ago I made an email campaign editor using JavaScript, I re-implemented it in CoffeeScript a few months ago. What I now want to do is re-implement it in the good JavaScript I've learned from reading the code that CoffeeScript generates.
There are some annoying parts of CoffeeScript. If your function takes callbacks as the first parameters, and another value as the second (such as setTimeout), you end up with some really awkward syntax. I've seen a lot of people define a delay method that swaps the parameters of setTimeout just so it's easier to use with CoffeeScript.
Like the author of the article, I have a Python background, but I've also written a lot of JavaScript, I love the syntactic sugar that CoffeeScript brings, but I hate reading CoffeeScript code. The project that my re-implemented email editor is used in has a hybrid of JavaScript and CoffeeScript code, and I'm not kidding when I say that everyone (myself included) groans when they have to work on the CoffeeScript parts.
To me, this says that you should define your callback as a function, and pass the function. If you're used to how to write functional code, this can be a clean way to do things.
Making the callback the last parameter is very common in JavaScript too. It just makes things look nicer when you want to put anonymous functions in there. Underscore.js does this for all their functions.
> If your function takes callbacks as the first parameters,
> and another value as the second (such as setTimeout),
> you end up with some really awkward syntax.
Hopefully no more awkward than the equivalent call in JavaScript.
But here we're introducing brackets just to avoid the syntax ambiguity. The Pythonista in me is crying out for a single way of doing things, either require brackets or don't. It makes me want to go down the road of always using parenthesis in CoffeeScript, but then it'll feel like I'm not using the language in an idiomatic way (which is something I hate doing).
In my mind, this usage of parenthesis is less ambiguous. Parenthesis are used in C-like languages for both function calls and order of operations. That is to say, they are used in these two ways:
foo(a, b, c) // functions
(a + b) * c // order of operations
Making parenthesis optional for function calls means parenthesis are used instead for just controlling order of operations.
In practice, CoffeeScript can't always guess when something is a function call (such as a function call without arguments), so you end up mixing in some function call usage no matter what.
In my experience I would find myself frequently falling back to explicit brackets and more traditional Javascript syntax when I wasn't sure how to construct the statement. Which was okay (I wasn't stumped), but it happened fairly often. Your multiple line example (without "function") is the kind of thing I wouldn't be able to create on my own – both the indentation and comma have to be in just the right place, and the rules that govern that are not very clear. Or rather, it seems to be the one thing that works given a bunch of rules that are interacting in that particular situation. And each time I'd get something like that wrong it'd probably compile, but then I'd have to read the generated source to see what I'd actually done.
As for `delay`... I had to think hard to think why would it be a bad idea and concluded that it is non-standard and can confuse readers. If this is the case then just define a `swap` or `flip` function, along the lines of
Using CS for about 1.5 years now.
Yes, there're ways to hurt yourself with bad CS code. This is also true for Python.
When developer writes some fancy one-liner in CS or Python and I'm reviewing his commit, I just ask him to come over and explain what this thing is doing. Sometimes it takes more than 20 second to read and explain even by author.
Then I say: "You wrote this line an hour ago and it's already hard for you to understand what it does. Imagine you'll need to change it in a month. You'll hate yourself. Go and rewrite this code explicitly to help yourself in the future."
If you force yourself and teammates to write explicit code, you get all the pluses of CoffeeScript avoiding bad readability.
Some of the complaints in the OP aren't mistakes that I make often, so I guess I don't see them. Perhaps for someone that makes those types of mistakes often, it'd be a detriment, but so far, I've been happy with my coffeescript experience.
except when APIs get 100x bigger, API design becomes 100x more important. and using a language ecosystem that encourages good API design, over a language that is cobbled together and has no particular opinions about what good API design looks like[1] (or, even, bad opinions[2]), so that less experienced developers end up with decent output, is that much more important than concerns like parens, commas and braces. curly braces never made a project fail. shitty API design does.
[1] javascript!
[2] java!
sheesh. there are bad things about coffeescript, but this stuff hardly matters.
I don't have a strong opinion on the article itself (it seems well-reasoned to me, but I don't use CoffeeScript personally so who knows)... but the comments attached to it are hilarious.
I think CoffeeScript has great readability, because I’ve taken the time to learn how it works.
If you have to take the time to learn how to read something, it's not easily readable.
CoffeeScript is only hard to read if you try to read it with a JavaScript mindset.
Yes, why would anyone approach a tool pitched explicitly at JavaScript developers, whose "golden rule" is "it's just JavaScript" (see the top of http://coffeescript.org/), with a "JavaScript mindset"? Truly, it is a mystery.
> If you have to take the time to learn how to read something, it's not easily readable.
I don't think that's completely true. If you're used to algol or C-style, Lisps tend to be hard to read. Concatenative languages even more so. Not necessarily because they're hard to read in and of themselves, but because the "shape" of the code is "all wrong" compared what you're used to, and your usual anchors (keywords, binary operators, infix assingment, ...) are nowhere to be found.
I mean Arabic or Korean are not necessarily harder to read than English, but you've got to know them and how they work before you even recognize patterns in the squiggly lines and little squares.
Not really; Lisp is hard to read because the syntax is unusual, but it's not hard to understand because it's complicated. On the contrary, it has the most consistent syntax of any language.
They author's point is that Coffeescript is hard to read because it has too many edge cases which are not easily understood under a smalla and consistent set of rules. I have not programmed with CS, but it sounds like a convincing argument.
Or, to restate this and amplify it a bit, Lisp syntax is hard to read because most people are unfamiliar with it. This isn't -- or should not be -- a problem if you need to learn to read a language in order to use it. (This is orthogonal to whether you want to learn it in the first place, or whether you "ought" to.) It is a problem if learning how to read and write the language isn't enough.
The point TFA raises is that people who're familiar with CoffeeScript syntax may still make mistakes resulting in completely erroneous but valid code. Yikes. And the inherent nature of whitespace or indentation makes the problem harder to detect by cursory inspection.
I have no strong opinions about CoffeeScript, myself. I just thought this was an interesting distinction, and a rare case where syntax makes a significant difference.
Mere consistency is not enough. List is hard to read because humans do not have a natural feel for how deep a set of nested brackets are, and you have to be able to spot the matching open-bracket to understand the code.
Again, it's hard to read if you are not familiar with it. Even as someone relatively new to Lisp, indentation and formatting makes a world of difference for readability.
This isn't specific to Lisp, either. I posit that if you took your average C-like and removed indentation from any reasonably sized function or method (one or more loops, one or more if/else), you would have a hard time counting brackets.
I agree that consistency is necessary but not sufficient, though, which is what I think you're getting at. Most of the time, though, consistency is clearly better than inconsistency. There's less to remember or, if you prefer, less to screw up. :)
Please note that I was not replying to TFA, I was replying to smacktoward's assertion that if you need to learn how to read a language it's not easily readable.
i'll stick to javascript. coffeescript doesn't add a whole lot to the table, javascript is the standard and that's a good thing, re-writing the language is not the answer in my opinion.
i'd have to imagine that saving a few keystroke might sound sexy to lesser experienced developers, but that really is all it adds to the table.
being able to code on any project immediately off the bat with a standardized language is a huge plus, in terms of flexibility and scalability. you don't want to limit your company to exotic language, only to later find out few months later another new language called "frapscript" is now the new cool thing to do.
i recall the days when i was thrown into a project where the requirement was to use mootools, rather than jquery.
even though they are both "javascript" in nature, it severely limited my productivity. i can see the same thing happening to companies trying out coffeescript, it may seem like you are doing the better thing long-term wise, but in reality, it is not so much. it's better to just stick to standards and you'll be more productive down the line, i can almost guarantee it.
I'm not sure that this will ever be a fair statistic because coffeescript should never really be used for shared / module code IMO. I love CS for my application code but would never release a package on github in CS, only JS.
Once you are releasing things outside of your controlled/team environment using anything but JS is just a loop for others to jump through.
I imagine a lot of projects have both CS source for development, with compiled JS for deployment. That might skew the stats between JS+CS, but it's a good indicator of CS' popularity compared to other languages.
Considering that, releases would be in JS, as they should be.
So you had jQuery experience and were inhibited by working on a MooTools project. I get that, makes total sense.
But then you say that switching to CoffeeScript may seem like a better long term choice but "in reality it is not so much."
Surely MooTools would've been fine for you as a long term choice.
Yes, there is a penalty to switching. Whether it's jQuery to MooTools, JS to CS, whatever. But that doesn't make it a bad long term choice.
Also, CoffeeScript is more than just saving keystrokes. That makes it seem like it's all about initial up-front cost savings. Instead, it's about having shorter, more expressive code. That pays dividends for the life of a project.
"Instead, it's about having shorter, more expressive code."
yes, but at the expense of a lot of other negative baggages that comes along with it. by having it's own compiler rather than leaving that to the browser seems like it's opening a can of worms.
and just reading from the comments, i can see how we could soon see a birth of "another language", that's supposed to be solve all problems coffeescript'ers face.
for one, i guess readability seems to be the common problem, which isn't good for productivity.
There's a bit of a contradiction in your statement. MooTools is much more idiomatic than jQuery in it's use of javascript inheritance, object creation, etc, so it's "more javascript". jQuery is so efficient to work with because it created it's own nice DSL, not because it is standard. The standard could be C, would that make you more productive too?
it was a point that even if you are merely switching a js framework where both are written in javascript, productivity can drop.
if you now switch to coffeescript, something not remotely close to javascript or any other languages fwiw, you'll experience un-productivity. it's akin to having your top developers walking in eggshells and doing nearly nothing close to what he is capable of.
i think coffeescript is great in the sense that we are trying to create a better language. but i also sense how much damage it can bring to budding startups who can't find talented coffeescript'ers to fill the void when their lead developer moves on to other things.
a one off go project, i'd say it's fine. but anything more complex, i think you'll see programmers wishing they had gone back to what they were familiar with.
What damage? You can drop it at any minute and start working on the compiled javascript. I've done this a couple times.
That's true for any tool/language/platform/whatever, everything has a learning curve (and coffeescript's is quite short). Going by your words we shouldn't ever learn anything.
And you shouldn't switch to a language if your developers are not comfortable with it. Do some experiments, try it out on a smaller project, then you might switch if you see good results.
If you're used to one C-style language, it's generally not hard to read code written in another. This is not to say that you'll grok it 100% accurately on your first go, but another C-style language will be more readable to you than, say, a Lisp-flavored one would be.
Of course that "readability" leads to devs writing C in Java, or what have you, and naking subtle mistakes, instead of learning the new language. See Dijkstra's "On the cruelty of really teaching computer science"
Of course that "readability" leads to devs writing C in Java, or what have you, and naking subtle mistakes, instead of learning the new language. See Dijkstra's "On the cruelty of really teaching computer science"
So is mathematical notation not readable? On the one hand, it takes quite a while to learn how to read it. On the other hand, it can condense literally pages of text into a few equations which somebody experienced can understand almost at a glance.
The same is true for programming languages. Sure, anybody can read Python. But it's fairly verbose and attempts to mirror English. On the other hand, Haskell is somewhat terse and attempts to mirror mathematical notation. I've found that, after about the same amount of time with either language (about a year of off-and-on use for both), Haskell becomes far easier to read than Python.
So just because something is easier immediately does not mean it is any more readable. It could, in fact, be less readable and merely more familiar!
Mathematical notation is not readable, no. It requires extensive training to be able to understand it, and even experts will take quite a while to comprehend a document they are not already mostly familiar with. It is not like you cross some threshold and immediately become able to understand all mathematical notation with equal ease. There's plenty of evidence for this; recently we had this quote about the ABC theorem: "It can require a huge investment of time to understand a long and sophisticated proof, so the willingness by others to do this rests not only on the importance of the announcement but also on the track record of the authors" (http://www.nature.com/news/proof-claimed-for-deep-connection...)
> even experts will take quite a while to comprehend a document they are not already mostly familiar with
Experts don't take time to read notations. They take time to understand the full scope of consequences embedded in a line composed of such a condensed and readable notation, within the frame of an otherwise complex proof.
> Mathematical notation is not readable, no.
I beg to differ. You mention the recent possible proof of the ABC conjecture, and I happened to browse through various materials on the subject. While I am far from being able to understand the crux of the proof, I can perfectly read the various components of it. In fact the notation system is so readable it actually helps tremendously in grasping concepts previously unknown to me.
Mathematical notation is much harder to read than prose. It does a very good job of serving as a mnemonic for something you already understand, and a very poor job of explaining novel (to the reader) concepts.
It's also as bad as natural language for ambiguity and informality.
I don't think either English text or mathematical notation is a magic wand for readable programming language; It's more about reducing accidental ambiguity and the amount of mental context needed for parsing 'natural' constructs in the language.
Personally, most of the benefit I see from mathematical notation is down to pattern matching -- "Oh, this looks like a Fourier transform". The idea seems to be supported by the fact that there is a unwritten convention for which symbols to use for which concept (alpha over beta for example) and the way in which the equations are laid out.
I concur with the author. When I write CoffeeScript I often use a more explicit or more c-like style for things I find ridiculously ambiguous or hard to parse when reading quickly.
Particularly, if one line has lots of commas, I put parens all over the place because no matter what I do, having to manually parse the comma arrangements and figure out what's nested and what's a function does not go quickly. I also find myself writing explicit returns somewhat frequently just so it's much more clear what's being returned.
The overarching issue is that the syntax blurs rather than pops -- there are too many instances where things that are significantly different in function look nearly the same.
This is a fantastic post -- I feel like I've run into all these crazy "gotchas" over the past year, and more.
And the worst part of it is, nearly all the confusing/ambiguous/different compilation examples given rely on the undocumented rules CoffeeScript uses for parsing. It's amazing that, still, CoffeeScript's entire documentation is basically a "getting started" guide, and there is simply no reference documentation.
I personally describe CoffeeScript as "stabby". CS has all these little shortcuts and shorthands which seem great and appear to save time, but many of them are ambiguous, and then you get stabbed by their ambiguity, and you waste time debugging. Python, on the other hand, is still quite concise, but is generally very unambiguous.
I always thought CS was a "kinda-python-y" version of Javascript, though I never actually used it. It surprised me, therefore, to see that the OP considers these two items to be principles applied to the design of the language:
- Implicit is better than explicit
- There is more than one way to do it
These are the exact _opposite_ of a couple of the principles of the design of Python[1].
Go is an excellent contrast. Not only is the syntax spartan, but--especially if you include the built-in formatter gofmt--it has a fascist insistence on a uniform coding style. I don't agree with all its stylistic decisions, but I'd rather live with them and have consistency than run into corner cases and gotchas.
I think CoffeeScript seems nice in theory, but in the end, it's something made for people who want to code javascript, without actually using the language. It exchanges some of the terse, functional elegance javascript offers for a different kind of elegance, with its classes and inheritance and such like.
I won't say it's bad, as it is nice to work with when you're writing it, and I do quite like it. But I could never recommend it to someone who didn't have a good knowledge of javascript already.
I don't believe it exchanges any of the elegance. You can do the same things in CoffeeScript that you would in JS, just with less typing. That being said, a knowledge of how the browser will execute your compiled Javascript is crucial.
As I wrote in the other recent CS thread here, I think your coding style must be ill-suited to coffeescript. I've had a few situations where I've had to test things out for myself, but nothing like what you put forth. I just write CS as I would JS and that's that.
To that end, the docs on Coffeescript.org are the reference documentation (as they are the only official documents to reference) and they've suited me just fine. I get the sense that you're looking for a document in the style of ECMA-262, rather than one in the style of MDN.
Right. I've started using CoffeeScript for a side project, and I really appreciate how it fixes most the warts in JS, but I wish they had stopped there rather than making gratuitous syntax changes. Parentheses in function calls is not an actual problem.
I'm afraid that in conjunction with significant whitespace, they're not at all gratuitous. For example:
describe 'Calculator', ->
it 'can add two positive numbers', ->
result = calculator.add 2, 3
assert result is 5
it 'can handle negative number addition', ->
result = calculator.add -10, 5
assert result is -5
Mandatory parentheses make significant whitespace lose much of its appeal when passing a block construct into a function. This is a large part of the reason why Python limits lambdas to a single line...
Valid point. Although I'm on the fence about significant whitespace in CS as well; I value fixing JavaScript's glaring flaws much more highly than arguably more convenient but unproven syntax. (The boundary is admittedly fuzzy, e.g. list comprehensions).
Optional parentheses wouldn't be so irritating if the rules for omitting them were universal. Currently, when calling functions with arguments you can omit the syntax, but when calling functions without arguments you must use parentheses. Could the 'dispatch vs variable reference' question be decided with some sort of suffix that preserves the value of whitespace? Something like 'f!' 'g! arg1, arg2'?
Sorry for the imprecision. It's the same thing to Python, in terms of significant whitespace. Language features that use whitespace for structure are not considered to be expressions, and can't be used as part of a larger computation. In CoffeeScript, they are, and can.
I think it would be interesting to see the operational semantics for a very small subset of the language. Applying that type of formalism would likely suss out or highlight the corner cases like the ones highlighted in the article.
Maybe coffeescript programmers could just use their brain and choose not to descend the Infinite Staircase of Obfuscation (the carrot's not worth it). Just because Coffeescript can saw your foot off doesn't mean you have to.
I have used CS on 3 projects and Scala in 2 projects. For me, both CS and Scala have terrible readability. Scala is more worse, I'll need at least 3x to read it than write it. Obviously, YMMV (tm)
Question: am I the only one who's driven nuts by "if"s that come after the "then" part? E.g.:
do_something(with, these, args) if im_supposed_to
I mean, the processor/interpreter always needs to evaluate the "if" first, so what purpose does it ever serve to put it after the "then"? To me, it just confuses things because it feels like code is getting executed backwards -- like crossing an intersection, and then checking to see if the light is green.
I know it works "in English" ("do this if that"), but when I scan other people's code I'll sometimes completely miss the "if" (sometimes it's just off the screen).
Are there any examples where this reverse-if actually helps, instead of harming, code intelligibility?
If may be strange because of the asymmetry but I'd actually prefer `if` to be come first all the time and `unless` to come last all the time - precisely because `unless` reads like it's for exceptional circumstances:
value = cache[key]
if value?
return value
return file.readContents() unless not file.exists()
Yeah. The example is not very good, as it would probably be better to write as switch expression. But on a complex function, returning early can avoid the need to retain a lot of context in your head while reading that code. I find it especially helpful for returning/throwing on error conditions or breaking out of recursion.
I personally find that I end up reading more lines of code than I need to.
When scanning and I see
If (condition) { perform_some_action(foo, bar, baz); }
And I know condition is false I can ignore what follows but
perform_some_action foo, bar, baz if condition
I now have to stop and parse the entire line. But not only that, because it can appear at the end I need to parse every line to make sure I don't get caught by some if or unless. Short lines are easy sure but it's still annoying to me.
But if we want to avoid it, we would be required to already know what's inside the parenthesis. If we already knew what's inside it, putting condition before helps more as in that case (1) Either it's true and you have to parse the block or (2) It's false and you just jump to the end of it.
Not at all true, most of the time you are reading code with a specific goal or area of interest in mind, and thus are only interested in the subset of code related to that purpose.
yeah I agree here as well, postfix anything is quite annoying to read, especially so when chained, and the absence of parentheses makes this even more terrible
... it helps to keep the expected main-line flow of your instructions reading smoothly -- much the same as the way you'd tend to use it in English. Doing it the "normal" way instead:
read(file)
if (!terriblyUnlikelyThingHappens) {
write(file)
}
return results
... makes it a bit more difficult to follow what should be going on in the function.
223 comments
[ 6.0 ms ] story [ 484 ms ] threadAny time you are writing code that is ambiguous, use what you need to in order to clarify it. Don't omit punctuation just because you can if it makes the code less readable.
Using empty parameters in a function declaration is even funnier; you're adding punctuation that makes the code more vague. Just omit it! The third example is totally valid, and one I completely agree with - omitting parentheses on inner nested function calls makes for unreadable code. Don't do it.The fourth example - complaining that inconsistent indentation produces inconsistent results - is just incomprehensible to me. When you're using a whitespace-delimited language, you'd best pay attention to your whitespace.
Ambiguities with optional curly braces are certainly nothing new to Ruby developers. Convention is that only the last hash in an argument list may have its braces omitted (or more stringently, a hash may only have its braces omitted if it is the last parameter in the list). Makes for finely readable code. Don't write unreadable code.
One of the fundamental rules you should follow when working in any language is "don't be clever". Optional parentheses can make for very clean code, but if you try to get "clever" with them, you end up with ambiguous code. List comprehensions are awesome but if you use them when there's a simpler construct you can use, you're doing it wrong.
You can write bad, unreadable code in any language. Part of maturation as a developer is learning to write readable code, not just working code. A bad workman blames his tools.
> Optional parentheses can make for very clean code, but if you try to get "clever" with them, you end up with ambiguous code.
Seriously? Using extra parenthesis to add clarity is being clever? I always thought it was being safe.
The OP had a fine example of "doing it wrong", with the nested inner function call without parentheses. While technically valid, it's bad code because it's difficult to read, even for someone accustomed to optional parentheses. Such a construct is "clever" when it shouldn't be.
It's akin to programming C and everytime you write a function, if statement or for loop you have to ponder whether it looks best to put the opening brace below the line or at the end of it. I hate reading code with an inconsistent brace placement style like that.
Yes, you can write bad code in any language. That doesn't mean that languages don't have an impact on the ease of writing good and correct code.
Style guides and best practices exist for every commonly used language, and not because of flaws in the languages themselves, but because unless there is literally only one way to do things, a dozen developers will come up with a dozen ways of solving a problem.
Yeah, that didn't work out so well.
There's a difference between style guides offering a well-lit path to follow, and a language having a large number of possible expressions that are off limits in practice because they lead to bad code. The former marks out a path, the latter indicates a minefield. When the language's design actually facilitates the creation of bad code, not just by offering the possibility of dangerously ambiguous expressions, but by touting that possibility as a plus, that's a flaw.
Maybe accepting that flaw is worth it because the expressiveness of the language makes it a net plus; doesn't mean it's not a weakness or flaw or a point to be cautious about.
Coffeescript is a very flexible language. Its flexibility lets you do bad things with it, but the flipside of that attribute is that you can do very good things with it. I don't think that it's either "a path or a minefield"; I think those are two sides of the same coin. Optional parentheses and whitespace delimiting can reduce visual clutter, but if you abuse them and reduce it too far, you increase cognitive load on the person that has to read and maintain the code.
The more stringent the language, the less guidance you need in the form of style guides and community standards, but that's simply because the language itself imposes those standards on you as a byproduct of disallowing flexibility. It's absolutely something to be cautious about, but it doesn't make the language inherently flawed.
The C style syntax situation with optional if brackets is almost universally considered a flaw:
This is not the flexibility to do hard things. It does not save a lot of typing or make some other common construct less cluttered. It is just a defect in the grammar that it's too late to fix.It sounds like Coffeescript has more of these flaws.
My own opinion is that syntactic flexibility does have value (e.g. Haskell). I think it's also vastly overrated relative to that value; syntax is incredibly easy to bikeshed. Semantics require you to know something about the languages at issue.
That said, my opinion is that this kind of syntactic flexibility offers dubious value if the trade-off includes not just obviously broken programs but also subtly broken ones with errors which are difficult to spot. Newbie errors are part of the learning curve, but these seem like mistakes even experienced people can make.
The problem is that there is a local maxima in the flexibility cost-benefit curve. After you reach that maxima additional flexibility degrades your experience.
For my personal projects or small teams I'd have no reservations using CoffeeScript if it felt like the best fit. For large teams, I'd reconsider.
No, it's "If a language that provides for many ways to write terrible code (incl many ways to write the same code), people will write hard to read code." For example if parens are required, it is impossible to "get clever" with not using them.
> A bad workman blames his tools
Great workmen evaluate and avoid bad tools.
A prime historical example being Perl. A second one being PHP.
The kind of problems that the article points out are easy to spot. If small syntax changes yield significant output code, that will be immediately reflect in the program execution.
Plus, a decent code base will have unit testing in place, which should catch more intricate, harder to catch, unwanted code flavors.
> Plus, a decent code base will have unit testing in place, which should catch more intricate, harder to catch, unwanted code flavors.
That's rather optimistic.
There are no absolutes. This is all subjective.
"OMG it's change, run away!"
If you're looking for more regular style, this style guide is a better place to start:
https://github.com/polarmobile/coffeescript-style-guide
Note: I'm not saying Crockford was singularly responsible for this, but The Good Parts was certainly well-received and very much popularised for it's opinionated views on the language.
Edit: I mean in terms of coding style, CS itself has already cut out a lot of The Bad Parts of JS
It's always good to look at the pro/cons before choosing a language, so I think discussions like this is good.
That being said, some of the problems this article points out can be addressed by going back to more JS style.
e.g. Not relying on implicit parentheses/commas/braces
I like the "Fancy" for loop because it's closer to what I do in Python (yes I know they are not exactly the same). Same thing with the "Tricky" if statements.
Also the redefinition shortcuts provided in CoffeeScript is pretty much what I do in plain JS anyway.
e.g.
JS: foo = foo || 'bar';
CS:
"Conditional assignment of previously undefined variables a or= b is now considered a syntax error."
It's useful for something like:
However a lot of criticism seems to come from the fact that the author is a Python programmer and therefor wants CoffeeScript to be more like Python. No, I am not saying something like the author not understanding it isn't meant to be Python, but for example the implicit vs explicit debate is certainly a more philosophical view. Ask people who prefer other programming languages and they will have a different view. Hey, after all that's why there are so many, even if Ruby, Perl, Python, Falcon, etc. have very similar use cases.
My opinion for example is that dynamic languages are very implicit in first place so saying you don't want that (at all) doesn't make too much sense. I also don't have problems reading CoffeeScript, but occasionally had problems with very explicit languages being too verbose which can make it harder to follow. So looks like my mind works slightly different here.
But back to the article. There are lots of valid points. I think coding guidelines, which one should have working in a team, no matter what language could solve some of them. Some points look a bit like mixing different styles on purpose and at least can't see how you could find something like that in the wild. Just because you can code ugly, it doesn't mean you have to, but again that is more of an opinion. Some people like usually verbose languages, because they say they are easier to read, others like ones with shortcuts or where you have multiple options to express things, making it easier to read (for some people). I for example always enjoyed the fact that Perl has unless and until in place of negated if/while.
But that's more what you prefer. But hey, CoffeeScript is all Javascript, so if your team doesn't like it it's (comparatively) easy to step by step switch back.
Many of the issues raised in this article can be solved by "simply" not doing it (admittedly not always a real solution). Just because the language allows something to be done, doesn't mean it should be done that way. Our team has a styleguide that clearly explains good and bad practice, for CoffeeScript AND Python. (It's possible to do bonkers stuff in Python, too, just harder.) It includes things like: use explicit returns, especially when intending to return nothing; include parenthesis unless it's more clear without them (callback as arguments).
Yes, it'd be great if the language were more explicit and made it harder to do confusing thing. But, its core goal is being "just javascript", which prevents some of that explicitness. Also, the flexibility lets the real goal be clarity.
I find
to be more clear than because it doesn't have all the crap. CoffeeScript's whitespace syntax is even more helpful when those objects start getting nested. Plus, not having to deal with trailing commas is amazing. At the same time, can be confusing, so parens help: I try to not be "that guy" when it comes to CoffeeScript, but it's easily one of my favorite languages now. All the crap that JavaScript requires is just gone.I think a majority can grok and parse Python, but the same can certainly not be said for CS. It's unfortunate too, because it has some Good Parts.
Readability is very subjective and depends on the user's knowledge of the language, as well as personal style, or 'accent', if you will. Code written with, for example, leading commas in dictionaries instead of trailing commas just looks bizarre to me and is a little harder to read, to me, even though I like to do something similar and stack colons.
someFn(arg1, arg2, (-> doStuffInACallback()), arg3)
But far better, if you have any say in it, is making the callback the final argument to someFn.
someFn arg1, arg2, arg3, -> doStuffInACallback()
The thing about coffeescript is that most of the pitfalls being discussed here are very easily avoided with a modicum of experience and sense, whereas in javascript, many of the core issues simply cannot be avoided, and must be worked around in plainly ugly and bug prone ways (see: string concatenation, this/that juggling, "])})]));, just for starters).
I just want to throw out a positive experience with it and to say that I don't support the author's premise of "here's some misleading things you can do with CS, therefore CS is unreadable". This applies to all languages, and 'fanciful' features and syntax should be avoided almost always in every language for the sake of readability.
There are MANY reasons not to use coffeescript, but JS is all functions all the time, and -> is my best friend.
Although it is all subjective aesthetics, CS shines when paired with underscore.js, and really all "callback-as-last-argument" paradigms, ie:
(edited formatting, also what alec said below :)I personally don't get excited by that prospect. Generators would get me excited, though!
made code a lot easier to debug. and yes, consistency wasn't the only thing. i would say that converting over has a learning curve sure reading other people's code. but sacrificing readability long term compared to vanilla js? i wouldn't say that. i'm not saying there isn't ambiguity in the beginning but eventually you learn how to not do things in ambiguous ways.
That is not enough, because unfortunately, there are more programmers in the world than "you", and I have to use their code and / or work with them.
When language has X options their is X! opinions on "consistent".
While nowadays I prefer coffeescript to js, I would rather have some syntactic sugar like scss is for css. I've looked into it but nothing has enough momentum to make me sure it will still be around in two years or so.
As a sidenote, while I mentioned I prefer CS, have you ever tried using a ternary operator? or pass a callback function in jquery (ex. the hover out event)? or just return "this". There are so many things that feel so wrong.
The reason why it works in the first place is for consistency ... in every other context, you can use an `@` to replace a `this` or `this.`.
And it's not like there's a warning about it being removed on coffeescript.org where it's being mentioned as an alias for this in the first place.
But that said, the last couple of projects I've written in pure JavaScript and it's actually made things much easier to go back and read. Like the author of this post, I too have had difficulty reading back over my old code and, at a glance, understanding precisely what's going on.
Over the past couple of months I've gone from being absolutely devoted to CoffeeScript to on the fence, mostly due to readability.
(I'd love to see a fork of CoffeeScript that forces syntax.)
A compiler option that enforces syntax would be nice.
When reading js, seeing the "var" really helps me to know the programmer's intent that this is a new variable being introduced, not an attempt to reassign one that should already exist. Does CS have features that make this point mute?
Yes. I've come to see it as a mistake in Python and Ruby both, and I'm definitely not pleased by its usage in CS. Even less so as it uses the same rules as Ruby's lambdas without the stops of its methods and global scopes.
This and that are completely orthogonal though, I've been using Python for 8 years and Ruby for 6 so I'm used to implicit scoping. Doesn't mean I like it, or find it a good idea to use it in new languages (I don't).
And the issue is actually bigger in coffeescript than in ruby and python both, interestingly because (through javascript) coffeescript's scoping is much more regular than Python's or Ruby's.
The only language in which I don't know implicit scoping to be an issue is Erlang, because it uses bind-once and immutable structure semantics.
> also because it takes away the nasty surprise that JavaScript gives you if you leave 'var' out.
That can trivially be fixed by linting, or using strict mode. That's really no argument.
Can you provide an example in js where knowing whether it's a new var vs. reassignment is useful? I can't think of a case, but it could just be me.
There are some annoying parts of CoffeeScript. If your function takes callbacks as the first parameters, and another value as the second (such as setTimeout), you end up with some really awkward syntax. I've seen a lot of people define a delay method that swaps the parameters of setTimeout just so it's easier to use with CoffeeScript.
Like the author of the article, I have a Python background, but I've also written a lot of JavaScript, I love the syntactic sugar that CoffeeScript brings, but I hate reading CoffeeScript code. The project that my re-implemented email editor is used in has a hybrid of JavaScript and CoffeeScript code, and I'm not kidding when I say that everyone (myself included) groans when they have to work on the CoffeeScript parts.
That said, I've seen the same problem myself.
In practice, CoffeeScript can't always guess when something is a function call (such as a function call without arguments), so you end up mixing in some function call usage no matter what.
Personally, CoffeeScript has been my favorite thing to come about in the past few years.
When developer writes some fancy one-liner in CS or Python and I'm reviewing his commit, I just ask him to come over and explain what this thing is doing. Sometimes it takes more than 20 second to read and explain even by author. Then I say: "You wrote this line an hour ago and it's already hard for you to understand what it does. Imagine you'll need to change it in a month. You'll hate yourself. Go and rewrite this code explicitly to help yourself in the future."
If you force yourself and teammates to write explicit code, you get all the pluses of CoffeeScript avoiding bad readability.
except when APIs get 100x bigger, API design becomes 100x more important. and using a language ecosystem that encourages good API design, over a language that is cobbled together and has no particular opinions about what good API design looks like[1] (or, even, bad opinions[2]), so that less experienced developers end up with decent output, is that much more important than concerns like parens, commas and braces. curly braces never made a project fail. shitty API design does.
[1] javascript! [2] java!
sheesh. there are bad things about coffeescript, but this stuff hardly matters.
I think CoffeeScript has great readability, because I’ve taken the time to learn how it works.
If you have to take the time to learn how to read something, it's not easily readable.
CoffeeScript is only hard to read if you try to read it with a JavaScript mindset.
Yes, why would anyone approach a tool pitched explicitly at JavaScript developers, whose "golden rule" is "it's just JavaScript" (see the top of http://coffeescript.org/), with a "JavaScript mindset"? Truly, it is a mystery.
I don't think that's completely true. If you're used to algol or C-style, Lisps tend to be hard to read. Concatenative languages even more so. Not necessarily because they're hard to read in and of themselves, but because the "shape" of the code is "all wrong" compared what you're used to, and your usual anchors (keywords, binary operators, infix assingment, ...) are nowhere to be found.
I mean Arabic or Korean are not necessarily harder to read than English, but you've got to know them and how they work before you even recognize patterns in the squiggly lines and little squares.
They author's point is that Coffeescript is hard to read because it has too many edge cases which are not easily understood under a smalla and consistent set of rules. I have not programmed with CS, but it sounds like a convincing argument.
The point TFA raises is that people who're familiar with CoffeeScript syntax may still make mistakes resulting in completely erroneous but valid code. Yikes. And the inherent nature of whitespace or indentation makes the problem harder to detect by cursory inspection.
I have no strong opinions about CoffeeScript, myself. I just thought this was an interesting distinction, and a rare case where syntax makes a significant difference.
This isn't specific to Lisp, either. I posit that if you took your average C-like and removed indentation from any reasonably sized function or method (one or more loops, one or more if/else), you would have a hard time counting brackets.
i recall the days when i was thrown into a project where the requirement was to use mootools, rather than jquery. even though they are both "javascript" in nature, it severely limited my productivity. i can see the same thing happening to companies trying out coffeescript, it may seem like you are doing the better thing long-term wise, but in reality, it is not so much. it's better to just stick to standards and you'll be more productive down the line, i can almost guarantee it.
Maybe saying it's widely accepted isn't entirely appropriate, but it certainly is gaining a lot of traction.
Once you are releasing things outside of your controlled/team environment using anything but JS is just a loop for others to jump through.
Considering that, releases would be in JS, as they should be.
So you had jQuery experience and were inhibited by working on a MooTools project. I get that, makes total sense.
But then you say that switching to CoffeeScript may seem like a better long term choice but "in reality it is not so much."
Surely MooTools would've been fine for you as a long term choice.
Yes, there is a penalty to switching. Whether it's jQuery to MooTools, JS to CS, whatever. But that doesn't make it a bad long term choice.
Also, CoffeeScript is more than just saving keystrokes. That makes it seem like it's all about initial up-front cost savings. Instead, it's about having shorter, more expressive code. That pays dividends for the life of a project.
yes, but at the expense of a lot of other negative baggages that comes along with it. by having it's own compiler rather than leaving that to the browser seems like it's opening a can of worms.
and just reading from the comments, i can see how we could soon see a birth of "another language", that's supposed to be solve all problems coffeescript'ers face.
for one, i guess readability seems to be the common problem, which isn't good for productivity.
That's called incremental progress a d most people see it as a good thing. Others yell, "Get off my lawn!"
Don't you find it a little odd that you have such strong opinions on something you've never even tried?
if you now switch to coffeescript, something not remotely close to javascript or any other languages fwiw, you'll experience un-productivity. it's akin to having your top developers walking in eggshells and doing nearly nothing close to what he is capable of.
i think coffeescript is great in the sense that we are trying to create a better language. but i also sense how much damage it can bring to budding startups who can't find talented coffeescript'ers to fill the void when their lead developer moves on to other things.
a one off go project, i'd say it's fine. but anything more complex, i think you'll see programmers wishing they had gone back to what they were familiar with.
That's true for any tool/language/platform/whatever, everything has a learning curve (and coffeescript's is quite short). Going by your words we shouldn't ever learn anything.
And you shouldn't switch to a language if your developers are not comfortable with it. Do some experiments, try it out on a smaller project, then you might switch if you see good results.
What? What language can you read without knowing it first?
The same is true for programming languages. Sure, anybody can read Python. But it's fairly verbose and attempts to mirror English. On the other hand, Haskell is somewhat terse and attempts to mirror mathematical notation. I've found that, after about the same amount of time with either language (about a year of off-and-on use for both), Haskell becomes far easier to read than Python.
So just because something is easier immediately does not mean it is any more readable. It could, in fact, be less readable and merely more familiar!
Other examples that highlight how understanding of mathematical research involves much more than just reading: https://docs.google.com/viewer?a=v&q=cache:5NM3XjxAWfUJ:... http://math.stackexchange.com/questions/13460/how-to-read-a-...
Experts don't take time to read notations. They take time to understand the full scope of consequences embedded in a line composed of such a condensed and readable notation, within the frame of an otherwise complex proof.
> Mathematical notation is not readable, no.
I beg to differ. You mention the recent possible proof of the ABC conjecture, and I happened to browse through various materials on the subject. While I am far from being able to understand the crux of the proof, I can perfectly read the various components of it. In fact the notation system is so readable it actually helps tremendously in grasping concepts previously unknown to me.
It's also as bad as natural language for ambiguity and informality.
I don't think either English text or mathematical notation is a magic wand for readable programming language; It's more about reducing accidental ambiguity and the amount of mental context needed for parsing 'natural' constructs in the language.
This is true for both CoffeeScript examples he gave and their resulting JavaScript.
Particularly, if one line has lots of commas, I put parens all over the place because no matter what I do, having to manually parse the comma arrangements and figure out what's nested and what's a function does not go quickly. I also find myself writing explicit returns somewhat frequently just so it's much more clear what's being returned.
The overarching issue is that the syntax blurs rather than pops -- there are too many instances where things that are significantly different in function look nearly the same.
And the worst part of it is, nearly all the confusing/ambiguous/different compilation examples given rely on the undocumented rules CoffeeScript uses for parsing. It's amazing that, still, CoffeeScript's entire documentation is basically a "getting started" guide, and there is simply no reference documentation.
1: http://www.python.org/dev/peps/pep-0020/
Compare with Go, where you can easily read the whole spec and keep the whole language in your head: http://golang.org/ref/spec
The "The Smalltalk Language" section of the last ANSI Smalltalk draft is a more reasonable 28 pages.
I won't say it's bad, as it is nice to work with when you're writing it, and I do quite like it. But I could never recommend it to someone who didn't have a good knowledge of javascript already.
To that end, the docs on Coffeescript.org are the reference documentation (as they are the only official documents to reference) and they've suited me just fine. I get the sense that you're looking for a document in the style of ECMA-262, rather than one in the style of MDN.
Python doesn't limit lambdas to a single line, but to a single expression. That is a rather different constraint.
I know it works "in English" ("do this if that"), but when I scan other people's code I'll sometimes completely miss the "if" (sometimes it's just off the screen).
Are there any examples where this reverse-if actually helps, instead of harming, code intelligibility?
And anytime there's code after a return, it had better be connected to a conditional. :)
When scanning and I see
And I know condition is false I can ignore what follows but I now have to stop and parse the entire line. But not only that, because it can appear at the end I need to parse every line to make sure I don't get caught by some if or unless. Short lines are easy sure but it's still annoying to me.