Hacker News new | ask | show | jobs
by mrinterweb 4153 days ago
The reason that I like CoffeeScript is that it removes, what I consider, the unnecessary boilerplate of JavaScript and replaces it with a shorthand equivalent and good conventions. I feel that CoffeeScript is better at representing the intent of JS than JS. I can visually sift through CoffeeScript and understand the code much quicker than normal JavaScript, which in my opinion leads to more maintainable code. I'm not certain what is appealing about reading and writing more code for the same result.

Many people don't like that CS needs to be compiled. I don't see this as an issue since pretty much every application I work on these days is concatenated and uglified. So adding a JS compiler is already part of most JS application's build process. 6to5 is being compiled to ES5 anyway. Also, if you include in your build pipeline a source mapper, debugging is not a problem.

6 comments

Ex-Coffeescript ,now Javascript with lot's of Python experience guy here.

The "I understand CS code much quicker" argument is a valid one theoretically, but In my opinion, it does not hold up practically that well.

CS got one thing wrong that Python got right: There are many ways to do things.

When writing CS, I understood MY CS just fine... but it always took me longer to understand the CS of other people. Sometimes even longer than JS. This is such a huge drawback, and even if there is coffeelint, for teams, this is deadly.

A lot of devs need to read a fair amount of foreign code. Even worse a lot of coffeescript writers also need to read and understand a lot of JS code.

Understanding and reading YOUR code slightly faster gets mitigated by having longer to understand foreign code.

While some JS purists fail to see that Coffeescript has some benefits, CS people also underestimate how "quickly" you can understand JS code, if you're experienced. It's all about what your brain is trained to do.

In my opinion, with ES6, I would argue for most people (ceteris paribus) it just makes sense to read and write JS exlusively, if you want to maximize output-productivity of a full, practical project.

Shaving off a couple of seconds "understand-time" of your personal, well written CS vs well written JS will just not compensate other things that will take you longer to do with CS.

As an example that I deal with daily, writing React components in CoffeeScript v.s. Javascript really highlights the elegance of CoffeeScript.

Of course you can reduce the JS verbosity with JSX instead... which again is introducing a pre-processor to the mix (one I personally am not a fan of, but w/e).

ES6 adds some sweet stuff for sure, but IMO it doesn't make JS a pleasure to work with yet (which seems to be the argument?).

I'm willing to bet it's not going to reduce the count in this list by much. https://github.com/jashkenas/coffeescript/wiki/list-of-langu...

I'm comfortable writing either as I'm sure many are, but when given the choice I opt for CoffeeScript.

P.S. Good luck telling someone using ClojureScript that they should switch back to Javascript.

"it doesn't make JS a pleasure to work with yet (which seems to be the argument?)"

My interpretation of what Retozi is saying is that CS just means that in addition to understanding JS, including ES6, you need to be familiar with all the different ways things can be done in CS.

I tend to agree, especially as JS is becoming an improving with each release.

What I'd like to see going forward is JS continuing to add selective sugar as is in CS, but also add functionality that makes going into a new fresh JS codebase and making sense of it easier. That side of things is less about CS, and more about the sorts of ideas you see in Dart and TypeScript.

My experience is the exact opposite. I find that CS removes a lot of the JS gotchas, and I'm not clear on the many ways that CS let's you do something, especially in comparison to JS. If anything it protects you a bit, by trying to enforce some of the "good parts".

http://arcturo.github.io/library/coffeescript/07_the_bad_par...

To each his own, but to me CS has been and continues to be a complete and obvious win over JS. 9 times out of 10 the benefit outweighs the annoyance of requiring a preprocessor for me.

On the multiple ways, I was sure I read a post that documented them all and had me nodding along but can't find it, this one seems good though [1].

[1] http://ceronman.com/2012/09/17/coffeescript-less-typing-bad-...

Out of all of those points, it's really just the commas and curlies that I've found can lead to some confusion, in my experience at least.

I haven't come up with a better approach than simply agreeing on a convention with your team though TBH. It's not too bad when everyone's on the same page and familiar with the gotchas (same could be said for most langs).

I put together a post comparing some of the syntax differences as it relates to building ReactJS components in case you're interested: http://rapin.com/blog/2015/02/03/reactjs-with-coffeescript/

Given that JS itself has quite a few different ways to do things though, it's kind of a wash.

> CS got one thing wrong that Python got right: There are many ways to do things.

I don't think this is necessarily true anymore, if it ever was. For hash-like datastructures in Python, please choose between object/dict/namedtuple/enum. In JS/CS all higher-level manipulations are dealt with through functions, whereas in Python depending on the situation you need factories, decorators, metaclasses and so on. And on a purely practical level people are moving away from the standard library (instead preferring arrow, requests, various unittest replacements etc.) but you'll still want to know the stdlib equivalents in case you encounter them in other code... and I can keep going like this.

I'm not saying this is necessarily a bad thing, sometimes one-size-fits-all just doesn't cut it, I just don't think Python can lay claim to being a simple language anymore.

> There are many ways to do things

Hopefully you realize that most Rubyists will strongly disagree and think that's not a "problem".

What's with the specious slam on Ruby out of nowhere?

Don't forget, Python is the community that brought us "There's Only One Way To Do It".

My biggest problem is definitely the source maps. It took me forever to get them to "work" and while the stack traces are mostly correct, they're often off by a line number or two. This makes debugging ridiculously hard when the line numbers are just "close".

I know this might not sound like a big deal in the grand scheme of things, but I also don't think CoffeeScript really improves on js all that much, so the annoyances of source maps are just not worth it to me personally.

Have you tried them at all recently? If a source map is off by a line, that's a bug that should be reported and fixed pronto.
I'm surprised. I use Browserify (and Coffeeify), which spits out a source map inline at the end of the file, which has not once given me problems.
That sort of thing completely killed any interest I would have had in CS. When it came about I already knew JS really well and the benefits of CS just seemed too minimal for learning a new language and dealing with bugs like that.
The things I hate most about CoffeeScript are the dash rockets and white-space significance. These are just opinions though. There are things I like about CS as well, like destructuring assignment and splats. Sometimes when I'm writing JS, I miss is, unless, etc... That said, I'd put my money on ES6 in the long run, though it doesn't really matter. People should use whatever makes them (and their team) happy and productive.
Significant indentation is a good thing. Haskell and Python do it too.

It's much easier to read indentation than it is to match up pairs of brackets in your head. In other languages, if the indentation doesn't match the brackets, you'll naturally read the indentation first and get the wrong impression of what the code does. In those languages, the indentation is supposed to match the brackets anyway. Why be redundant like that?

Significant indentation is enough for me to avoid Python. It just doesn't have enough to offer vs. the available alternatives without significant indentation.

It's much easier to read indentation than unindented/badly indented pairs of brackets, but you're setting up a strawman - it's not either or - and then you tear down the strawman yourself by pointing out we match the indentation anyway.

My code generally is properly indented and has start/end markers (though I mostly write Ruby, so rarely brackets), but what makes me stay away from significant indentation is that in the 30+ years I've been coding, I've never gone long without coming across situations where indentation has broken "in transit" e.g. with cut and paste between systems in annoying ways, or someone loading the code into an editor that butchers the indentation with tabs using "non-standard" tab settings.

When that happens, I'd rather "get the wrong impression" than have the code be broken.

That's one reason I want redundancy. My tools can trivially and automatically fix the result of breaking indentation when the indentation can be derived from the code.

Additionally, I want the visual redundancy, much like I find it far more comfortable to read syntax highlighted code even though it conveys no additional information.

I'm not setting up a straw man. I'm saying that it makes more sense if computers and humans are looking for the same things. Since humans read the indentation, computers should read the indentation too.

The way things are in bracketed languages, humans and computers read different things, and you just have to hope that they always match up. Sometimes they don't, and the human and computer will have a misunderstanding. To make it a real linguistic redundancy, like in Spanish, the compiler should read both and issue a warning if the indentation is incorrect or misleading. As it is, you and the computer are actually speaking different languages.

An easy solution to the tab problem is to use spaces instead. A good text editor will even let you use the tab key to insert a set number of spaces.
It's not just significant indentation. CS parses "f + g" differently from "f +g" (the former is an addition, the latter is a function call with "+g" as the first argument).
Yeah, the unary operators can cause gotchas.

Also, here's a gotcha I've run into where `a(b)` is considered different from `a (b)`

x a(b), c # => x(a(b), c);

x a (b), c # => x(a(b, c));

I like the indentation + braces redundancy because indentations are for humans, brackets are for the interpreter. Logic blocks are more explicit with brackets

I encountered a non-obvious Python bug that was caused by mixed spaces-and-tabs: to my human eyes, the indentation looked fine - the same as previous line, but the interpreter saw a different level of indentation.

> I encountered a non-obvious Python bug that was caused by mixed spaces-and-tabs

This is why PEP8 exists and people are supposed to follow it. Additionally, mixed spaces-and-tabs is a bug that causes poor readability - there's plenty of people who have their editors set to have tabstops as 2 or 3 spaces rather than 4, and your code will look wrong in their editors.

If you think there's any issues with mixed tabs and spaces in your codebase, Python provides a tool to find out - tabnanny. Additionally, any context-aware code editor will display a warning. (If you're using Sublime Text, the plugin to use is SublimeLinter - I assume there's similar tools for vim and emacs.) You can even set spaces and tabs to display differently in many editors!

Just installed SublimeLinter. Thanks!

It puts some icons in the margins, but I can't figure out how to get an explanation of those icons. I see a bunch of !s next to my import statements.

True, agreed. Python has the -tt flag but, UI mistake, it should have been on by default. Or at least -t.
Python's lambda semantics are limited due to the syntatic limitations created by Python's significant identation. That's not an universal problem of significant identation, but Python's syntax has it. I don't know, CS, so I don't know if it creates any such limitation.

Also, computers don't deal well with it. It's a smaller problem than people don't dealing well with it (the alternative), but it's still a problem. Anyway, this is much more relevant to scripts that run inside a browser.

> Python's lambda semantics are limited due to the syntatic limitations created by Python's significant identation.

(nitpick: you seem to consistently use "identation" in place of "indentation".)

I'm pretty sure that plenty of proposals consistent with Python's significant indentation have been proposed; python's lambda syntax is limited due to the BDFL not being convinced of the utility of more capable lambdas over using named functions enough to want to make Python's syntax more complicated to achieve it.

> Also, computers don't deal well with it.

Computers deal fine with it.

> nitpick: you seem to consistently use "identation" in place of "indentation".

Consequence of English not being my first language, and "indentation" being way too similar in it. I just can't spot the change.

I've seen a couple of proposals, yes they'd work, but they seem to be always ugly. But the problem is not that significant indentation makes it hard to create lambdas (Haskell's ones, for example are fine), but that it's hard to think about rules that won't create some kind of problem. On Python it's lambdas, on Haskell it's that they are often actually harder to write than explicit blocks (good thing Haskell has explicit blocks too).

And no, computers don't deal fine with it. To minimise some Python code you need almost an entire Python parser. Assembling Python code from small pieces (something that is really important for Javascript) is a frightening problem.

> And no, computers don't deal fine with it.

Sure they do.

> To minimise some Python code you need almost an entire Python parser.

I don't think source-to-source transformations requiring a parser for the source is an indication that it is problematic for computers to handle something. I mean, to execute the source code you need a parser, too, and no one says that needing a parser for execution is a sign that computers don't handle a language well.

> Assembling Python code from small pieces (something that is really important for Javascript) is a frightening problem.

Sure, assembling by cut-and-paste is a problem with significant indentation, especially when using media (like the web) which do not respect indentation well.

OTOH, using significant amount of cut-and-paste coding (rather than reuse by library code) is a sign of a problem with the language, development process, and/or execution environment, anyway, so I don't see it as a particular problem that a language structure isn't friendly to copy-paste coding.

I'm sure this has been argued to death but the counter argument is invisible formatting changing behavior is a bad thing. Sure if you get your entire team to use spaces or the same tabs great but passing open source code around to lots of programmers some of which use tabs and some of which use spaces ends up leading to wasted debugging time when someone used a tab where they should have used a space or visa versa.

On top of that I find it invaluable to be able to space out debugging code. Example

    void SomeFunc() {
       int x = doSomething1(1, 2, 3, 4);
       int y = doSomething1(4, 5, 6, 8);
       int z = doSomething1(5, 6, 7, 9);
       printf("xyz=%d,%d,%d", x, y, z);
       int a = doSomething1(0, 2, 3, 4);
       int b = doSomething1(1, 5, 6, 8);
       int c = doSomething1(2, 6, 7, 9);
       printf("abc=%d,%d,%d", a, b, c);
       int d = doSomething1(6, 2, 3, 4);
       int e = doSomething1(5, 5, 6, 8);
       int f = doSomething1(7, 6, 7, 9);
       printf("def=%d,%d,%d", d, e, f);
       return x * y * z + a * b * c + d * e * f;
    }
vs

    void SomeFunc() {
       int x = doSomething1(1, 2, 3, 4);
       int y = doSomething1(4, 5, 6, 8);
       int z = doSomething1(5, 6, 7, 9);
    printf("xyz=%d,%d,%d", x, y, z);
       int a = doSomething1(0, 2, 3, 4);
       int b = doSomething1(1, 5, 6, 8);
       int c = doSomething1(2, 6, 7, 9);
    printf("abc=%d,%d,%d", a, b, c);
       int d = doSomething1(6, 2, 3, 4);
       int e = doSomething1(5, 5, 6, 8);
       int f = doSomething1(7, 6, 7, 9);
    printf("def=%d,%d,%d", d, e, f);
       return x * y * z + a * b * c + d * e * f;
    }
On a long functions I find it much easier to see/find/delete the debug print lines by indenting them separate from the real logic but I can't do that on any language that enforces code blocks by indentation.

Commenting out also because an issue

    void SomeFunc(int v) {
       bool doit = v > 5;
       if (doit) 
       {
         DoSomething();
         DoSomethingElse();
         DoSomethingOther();
       }
    }
For testing I often want to comment out the if

    void SomeFunc(int v) {
       bool doit = v > 5;
       //if (doit) 
       {
         DoSomething();
         DoSomethingElse();
         DoSomethingOther();
       }
    }
If I was in python I can't do that

    def SomeFunc(v):
       doit = v > 5
       #if doit 
         DoSomething()
         DoSomethingElse()
         DoSomethingOther()
       
Error! I have to format the whole function just to comment out a line for testing. Yes in this case I could put `if true` (then requiring two changes instead of one) but there are plenty of other cases where code blocks by indent make it really annoying to work with my code.

So no, significant indentation is not a good thing.

Python 3 does not allow you to mix spaces and tabs. I don't know if Coffeescript is similarly strict.

I guess you've developed a habit where you're completely OK with having incorrect indentation a lot of the time, whereas I can't stand it. Just because it's easier to read for you doesn't make it easier for everyone, especially beginners.

I can't stand incorrect indentation either, but my experience is that it regularly happens anyway, and I'd rather not have that break my code.

And "incorrect indentation" has a very different meaning when the indentation is purely for presentation: As illustrated above, some people like to use the indentation to call out specific aspects of the code. That may be "incorrect" from Python perspective, but it is a way of visually providing additional information that is not available to you if you use a language that requires a specific indenting style.

I want to love whitespace significance, but after hitting refactoring pain points many times in Python, Coffeescript, and Sass/Less/Stylus, at this point I believe the brackets are worth their redundancy.
I love coffeescript, but it seems like the source maps are still pretty garbage. I often have to turn source maps off just to make Chrome's debugger not act so crazy. When I click to place a breakpoint in the original coffeescript code, it'll show up somewhere pages off from where it should go, and it just won't let me put breakpoints at certain lines.
I totally agree, but have you read the ES6 changes (i.e. what the article talks about)? To me, ES6 provides 90% of the good parts of CS, but without some of the tendency to let people write some of the headscratchers CS allows for.
If you've got any sort of programming skill your js will only be concatenated on test and production builds, not on development.

Your last paragraph makes little sense as you should never, ever be debugging a problem on live and I think minification has caused me a problem like twice in the 8 years since it's been popular. And it was pretty obvious when it did as the is wasn't even compiling.

> you should never, ever be debugging a problem on live

Until you have to

Then you've done it wrong. Very, very wrong. You should be able to replicate your live environment locally and not being able to is a sign of a very broken development process.

I just cannot emphasise this enough. One of my skills is debugging, everywhere I've worked I've been one of the top debuggers if not the top debugger.

Never, ever debug on live. If you can't recreate the problem locally, you don't understand the problem yet. Keep trying to replicate it until you do. I'm talking days of trying, not 10 bloody minutes.

The key to all debugging, the very fundamental skill, is consistent replication. If you can replicate a problem consistently, you can fix it.

There's a class of problems where this isn't necessarily true, especially for desktop apps, but web development problems and javascript, you can almost always replicate locally.

Sometimes your problem turns out to be a problem with production hardware or wiring, or depending on interaction with external partners who may not be able to replicate their interactions accurately for your dev/test environment, or otherwise impossible for you to replicate in dev/testing without already having figured out what the problem is.

While I agree with your overall sentiment, in any kind of remotely complex environment you sooner or later come across problems that you have no sensible way of reproducing in dev, and which will require you to debug on a production environment without it saying anything about the quality of your development process.

Bollocks, even in complex environments you should be able to test it outside. You can hook dev machines up to external partners, so there's absolutely no good reason to be using live environments for those problems.

I have seen production hardware or wiring be the problem once in my entire career. And I used to work for a company that ran and supported enterprise software on hundreds of different client-owned servers.

Most people these days will be running a few web servers at most.

EDIT: Worse still, we're talking about debugging javascript here, which makes what you're saying even more preposterous. Wiring, indeed.

> Never, ever debug on live. If you can't recreate the problem locally, you don't understand the problem yet.

I am guessing you have not been exposed to highly complex live environments. What you say is largely true but you state it as an absolute fact, which is a bit naive. Live environments tend to be far more complex than test or local environments and sometimes that complexity is what creates the bug. Sometimes the only solution is to debug live, but of course that is a last resort.

For 99% of programmers who aren't ever going to deal with the really tricky problems, it should be gospel.

I'm not naive, I did actually say "almost always" and "There's a class of problems where this isn't necessarily true", but perhaps you can't read?

> Then you've done it wrong. Very, very wrong. You should be able to replicate your live environment locally and not being able to is a sign of a very broken development process.

I feel this is statement is a tad hyperbolic.

One of my key skill sets is debugging, I'm pretty good at it. One of the things we can't do is completely replicate a production environment because we're a web hoster. Sure I can run and test stuff against our OS "gold images" but when you've added third party client code running on 300-400 sites on a single server that environment is not reproducible without a herculean effort. We also don't have the luxury of time to "Keep trying to replicate it until you do. I'm talking days of trying".

Four or five times a year I need to dig out ADPlus, point it at a customer's worker process and tell it to snapshot and dump when certain conditions/triggers occur. I then whip said dump over to my WinDbg+SOS environment to find out what the hell was happening in the process when it went bad.

I think there's a lot true in what you've written. However the root cause fix applied in a development environment is not always the fastest way to stop a user facing problem. Things get weird on live servers. I'm not suggesting altering code willy-nilly but a solid knowledge of production (logging, service status, etc) can lead to more effective debugging scenarios and faster time to resolution when things do go bad.
>If you've got any sort of programming skill your js will only be concatenated on test and production builds, not on development.

Development builds should use concatenated and minified .js code. That verifies that the development build performs exactly like the production build.

You can use source maps to help with debugging.