Why CoffeeScript Isn't the Answer
walkercoderanger.com
walkercoderanger.com
In CoffeeScript, ambiguous code is the rule, not the exception. On top of that, things like variable capture and everything-returns-a-value introduce new kinds of bugs. The author says "realistically, the issues I have raised with CoffeeScript don’t come up every day," but in my experience they pretty much did.
But the real kicker on top of it all is that none of the stuff is documented. When you're trying to guess if you should use parentheses or a comma or an indent or a newline or a backslash or what, there are no reference documents to help you. The CoffeeScript home page just has a bunch of tutorial examples which give you an overall idea, but there's nothing rigorous, and the devil is in the details when you start combining aspects of the syntax.
In the end, I'm much more productive programming in JavaScript because I know exactly how the language works, no surprises. JavaScript has its fair share of warts, but you take a day or two to learn them, and then you never need to worry about them again. CoffeeScript, on the other hand, is just endless surprises. And I still felt that way after a whole year of using it at work. It's basically unlearnable -- no matter how much experience you have, you constantly find yourself pasting different versions of a line into the "try" tab of http://coffeescript.org/ until you get one which, through trial and error, turns into the JavaScript code you want.
So you would use curly braces and commas to specify an object, and then be confused when CoffeeScript doesn't get it?
After a year you didn't figure out that its a best practice to leave off the parenthesis in just the outermost function call, but to include them in the other calls on a line to make things clear?
After a year, you didn't realize that with the CoffeeScript scoping rules, you couldn't just throw in a global at the last second without looking carefully to see if it was used somewhere else?
After a year, you still hadn't learned about function binding with fat arrow?
After a year, you still hadn't learned that the existential operator (?) means you don't have to use typeof nearly as much?
Section "full of surprises": http://ruoyusun.com/2013/03/17/my-take-on-coffeescript.html
http://ceronman.com/2012/09/17/coffeescript-less-typing-bad-...
And here's an old HN comment of my own which described a few representative difficulties: https://news.ycombinator.com/item?id=4518892
Also, there's no such thing as a global in CoffeeScript (unless you explicitly specify window.xyz), since everything is scoped to the file. And that's the point -- it's ridiculous to have to "look carefully" at all your code to see if functions further down share a variable name inside of them. In JavaScript, you don't need to worry about that because you know "var" scopes each variable to its function, regardless of whether a higher function or global variable uses the same name. In CoffeeScript, you suddenly do have to worry about that, which is fairly insidious and bug-prone behavior.
So you are saying that none of those particular issues are problems you are having today with CoffeeScript or were problems for most of the year?
In which case, what problems did you have?
Edit: it looks like in another thread you are pointing out some random and unmaintainable code examples that are ambiguous and saying that its hard to know how they will be interpreted by the compiler. Its hard to know how those examples would be interpreted by anyone, or why you would write code like that and create that problem for yourself.
The lack of explicit scoping is horrible, and the lack of actual named functions is annoying.
The only thing I use now is JSX (when doing ReactJS), or TypeScript when not using JSX, as that adds actual value.
# BROKEN
func 5, {
event: (e) ->
if e.something
36
else
45,
val: 10}
Anyone with more than a day's experience with CoffeeScript knows that it's much better to express this with the simpler: # far better
func 5,
event: (e) ->
if e.something
36
else
45
val: 10
Note how just dropping the excessive notation makes the intention clearer while also making the code cleaner.His example on variable capture neatly illustrates a few of the opinions of CoffeeScript that actually make it far easier to reason about code: don't use global variables, and if a variable has the same name, it should refer to the same thing. It's far more confusing to allow rampant variable shadowing. Code that relies on variable shadowing is simply broken.
His last example shows a fundamental misunderstanding of not just CoffeeScript, but JavaScript generally. Granted `this` binding can be sometimes confusing, which is why CoffeeScript has a fat arrow (`=>`) to automatically capture `this`.
He obviously knows a lot more than "day's experience".
If you make the argument that he needs to learn to write better CoffeeScript then you're lending help to his argument.
In this case, it's logical that a comma doesn't go there. A comma would go after the closing `}`, which is optional (and so are commas in objects). If you don't know the rules of a language, I feel like it's easier to criticise wrongly.
I think the point is that CoffeeScript does fix some problems of JS, but introduces complications of its own. It's worth it for some, but not others.
It took me months to really get used to CoffeeScript, and I certainly left in a few unnecessary commas after the first day.
The rest of what you wrote I agree with.
But I think the problem is that people are dismissing CoffeeScript before they have learned it, just like I did originally.
I now vastly prefer to use CoffeeScript (or rather ToffeeScript these days, but thats another issue) whereas initially I thought that CoffeeScript was a joke.
Then I had to learn CoffeeScript because it was used in a library that I needed to understand.
It was only _after_ I had invested the time in learning CoffeeScript that I could see the advantages. In fact, up until that point that I had learned it, CoffeeScript _was not_ an advantage for me -- it was a liability, because I didn't know how to use it. When you aren't familiar with a language then whatever advantages it may have are more than offset by the fact that you don't know what you are doing.
I think this is a problem that pretty much every new paradigm shares to some degree. It is very difficult for the average person to emotionally get behind the effort to learn a new way of doing things, and psychologically we just aren't wired to make an accurate judgement about whether that will pay off.
Judgments and decisions are actually emotional/subconscious and the rationalization comes afterward.
The argument you make regarding learning a new language is solid, and I think it can also be applied to new libraries, design patterns or even just coding standards. Now that I think about it, the backwards judgement -> rationalization strategy is one of the more pressing problems facing society, and I was guilty of it just as much by judging the OP first and rationalizing second.
i've been on so many RoR interviews where i am dismissed essentially for not knowing enough of cutesy syntax tricks and yet in the Java + plain ol' javascript projects i've worked on I've been exposed to a muuuuuch wider variety of programming design patterns than i ever was in Ruby-land, to the point where i could care less about the tiny semantics these hipsters spout on about
one of the few new languages i'm interested in working with now is Clojure simply because they cleanly define libs & then don't have all of this obsessive "syntactic sugar" nitpicking. to make a language / code library usable it shouldn't depend on developers going down a rabbit hole of brackets etc. I understand this is difficult to avoid in the "compile to js"/language pre-processor community but it's why I prefer Dart as a solution. It is an attempt at a clean, robust, simple language rather than a repeat of the annoying language evolution process where devs in the know just talk down to those who don't care to commune with punctuation all day
If someone can reasonably choose to formulate something, and for that formulation to pass static verification but do something totally unexpected, the language is at fault, not the author.
It does and the consequences are scary.
I've been hit by the scoping rules many times, but every time I ask myself why I'm using identifiers like i, j or x to refer to different variables in nested scopes anyway. Names like that should be reserved for only the tightest of scopes.
Is there another aspect of the scoping rules that you're referring to?
Implicitly scoping variables to their lexically-outermost point of use is a terrible solution, though: changing anything in any outer scope can completely change the meaning of code in all nested scopes. That's really really bad.
A much better syntax would is to require the 'var' keyword to denote the scope of every variable, but reject shadowed symbols at compile time.
Technically, Coffeescript should know better than to balk at the braces that is abstracting out when they're explicitly declared. And any compiler is going to groan when it gets to that dangling comma.
You're right that the comma was the real tragedy. I removed the braces to help illustrate how taking full advantage of the features of the language makes the code stronger. Strictly speaking removing the comma was all that was necessary.
I think you could have made your points just as strongly without attacking the author.
func 5,
val: 10
event: (e) ->
if e.something then 36 else 45Ambiguous code is a poorly thought out contrived example with a simple solution.
To me, this:
eat food for food in foods when food isnt 'chocolate'
Is kind of beautiful and much more readable than: for (var i = 0, var len = foods.length; i < len; i++) {
var food = foods[i];
if (food !== 'chocolate') {
eat(food);
}
}
How is this even an argument?: "One wouldn’t realize it was conditional until reading the end."
How do you expect to understand any code without reading it?
How do you understand people when they talk without listening? And the whole paragraph is moot with syntax highlighting.Variable clobbering is javascript's problem not coffescript's.
ECMAScript 6 introduces a syntactic sugar for classes as well as like every single JS framework.
Knowing plain old JS is important, especially for understanding CS. CS is just a tool that some people find useful, I don't really understand the passion or frustration.
That might be because I have been doing curly brace languages for a decade but tells me more, Foods is an array, not an object.
The word isnt as a keyword also makes me want to scream inside a little every time I see it:)
That said you are totally right, It's a tool in a category of tools I never really got into.
foods.filter(function (e) { return e !== 'chocolate'; }).forEach(eat);
Regardless, I disagree that the Coffeescript example is more readable. My brain is much faster at parsing symbols (`(`, `{`, etc.) than english words.With your JS example, without having to read the words, I know there's a loop, a conditional and a function invocation. I also know that I can safely add statements after this piece of code without worrying it might break some other function (in Coffeescript, I'd have no way to tell if the implied return really mattered or not assuming it was the last line of a function).
With your CS example, I have no way to tell what's going on until I've read the full sentence. I have to read every word and see if it matches one of the many reserved keywords in order to determine if it has a special meaning or if it's just a regular variable.
In Javascript, you have a few reserved words but the list is relatively short and those words are almost always preceded by a line break or a symbol.
Maybe our brains work differently...
Not to mention that filter/each functions will get even easier to parse once es6 standards reach the browser (stabby procs, woo).
I'm not trying to be inflammatory at all just wondering as this is a reply to my comment.
Also the CS reserved word problem you speak of surely isn't harder than learning to program in the functional style. I mean come on. ;)
tokens = []
for name, alternatives of grammar
grammar[name] = for alt in alternatives
for token in alt[0].split ' '
tokens.push token unless grammar[token]
alt[1] = "return #{alt[1]}" if name is 'Root'
alt
Why is a loop assigned to a variable? I understand that loops are expressions but the intent here is not immediately clear and definitely requires some thinking. That's what I mean by readability (terseness is another thing).One the one hand you have pragmatic, loosey goosey languages like perl, javascript, ruby, even scala and C#. An important defining characteristic being perl's maxim "there's more than one way to do it".
On the other hand you have what I'd call the "bondage and discipline" languages like python and java. The defining characteristic being "there should only ever be one right way to do a thing".
In my experience people coming from the 2nd world have a harder time living in the 1st than vice versa.
However:
python's "B&D" principle is more accurately stated as TSBOAPOOOTDI" (There Should Be One And Preferably Only One Obvious Way To Do It) and that's not quite the same as oft quoted (over?) simplifications such as "there should only ever be one way".
Similarly the Perl community TIMTOWTDI's principle has a related variant TIMTOWTDIBSCINABTE (There Is More Than One Way To Do It But Sometimes Consistency Is Not A Bad Thing Either).
Reflection and annotation processors in Java are very powerful tools; see Guice, Dagger, and AutoValue. Creating something like JQuery is awkward in Java, but it can be done; see GQuery. Java 8 will make functional and callback-heavy DSL's a whole lot easier to build.
Python may look like a strict language but it's not. You can redefine just about anything except the core syntax. If you want to make your head spin look into metaclass programming.
Haskell is a weird one; statically typed, but extremely expressive. It's very easy for Haskell programmers to define their own obscure notations and like when reading mathematics, you must understand the definition of every symbol or you're lost.
One interesting dimension is the attitude towards modifying other people's libraries. In Java, it's easy to build something that nobody else can change unless they fork the library and modify the source or mess with the bytecode. But if you build your own, you can do what you want. In more dynamic languages, you can load someone else's library and muck with it at runtime.
I can't believe you just compared python to java for B&D. Which language forces you to catch ever exception raised?
What is the question for which CoffeeScript is a compelling answer?
"I needed to speak to Germans, so I learned French and spoke through a French-German interpreter. Things were occasionally lost in translation and somteimes I couldn't get my point across, but French is prettier. Can I recreate this experience in code?"
"My team can't learn to write `var` or `===`. Can we just learn a new language instead?"
"Indentation speaks to my aesthetic sensibilities, but braces do NOT! What fits my needs?"
"I don't want to use JavaScript. Fortunately, since I never make coding errors, I'll never need to debug transpiled JavaScript. What's the right language for me?"
Seriously, though, what is the problem that CoffeeScript solves?
CoffeeScript obviously solves problems. Its not compelling to you because of status quo bias, and because you don't want to invest the effort to learn it.
The issue with equality is a real issue. CoffeeScript solves that issue.
Braces and parenthesis _do_ become awkward in JavaScript with callbacks. CoffeeScript solves that problem.
You have been able to debug CoffeeScript as CoffeeScript for some time now with source maps. However, debugging the generated JavaScript is not hard for someone who knows JavaScript.
It's your opinion that coffeescript solves the callback and parentheses issue. I'd also call your argument a bit of red herring.
... FWIW? I think futures do a mighty fine job of solving callback issues; no coffeescript needed. Design around them, don't make a whole new "dialect" for it..
e, personJson = fs.readFile! "person.json"
person = JSON.parse personJson
matchesLastname = myDB.query! "lastname", person.name
id = msgQueue.push! { JSON.stringify(matchesLastname) }
log.info "Message sent to queue: #{id}"
instead of this: fs.readFile("person.json", function(e, personJson) {
var person = JSON.parse(personJson);
myDB.query("lastname", person.name, function(matched) {
msgQueue.push(JSON.stringify(matchesLastname), function(id) {
log.info("Message sent to queue: " + id);
});
});
});
Why do you believe that it is better to design around serious issues rather than creating a new paradigm?I have found that the best solutions always involve a new/different fundamental model that incorporates solutions to recurring problems.
fs.readFile("person.json")
.then(function(e, personJson) {
var person = JSON.parse(personJson);
return myDB.query("lastname", person.name);
})
.then(function(matched) {
return msgQueue.push(JSON.stringify(matchesLastname));
})
.then(function(id) {
log.info("Message sent to queue: " + id);
}); var readFile = Q.denodeify(FS.readFile);
which doesn't create the promise. it just wraps the readFile method so that it returns a promise when you call it.What problems do you think coffeescript solves?
> "the + operator is still both numeric addition and string concatenation. That is frequently listed as one of the bad parts of JavaScript. Why no provide separate operators for the two?"
The problem isn't operator overloading: the problem is implicit type coercion.
Having to use 2 separate operators/functions for separate types when writing code, is useful only if types are actually checked at compile time, and the compiler can do inference on them (see the + and +. operators in F#)
If you have a dinamically typed language, you can have sane semantics if you make it so that type conversions are explicit (e.g. Python, Ruby...)
See also: http://james-iry.blogspot.it/2009/03/operator-overloading-ad...
Edit: And you didn't just disagree but call it a 'blatant absurdity' to blame the half of the problem that you happen to like better? Jeez.
In my defense, I didn't even think of having a language with type coercion and 0 operator overloading (even on builtin types). I never saw such a language, and I'm skeptical that it could work. But it's an interesting take on the problem.
I cannot say why I think that the no-coercion+overloading is the better solution... maybe that's because operators are dyadic, and thus type coercion can be executed on both sides of the operator, and multiple times. While function application is (can be?) sort of monadic (in the APL sense) since coercion/overloading for an argument doesn't depend on the type of the other arguments supplied to the function
(But while writing this, I'm not so sure anymore... at the very least, it could depend on the order in which arguments are evaluated...)
(Technically objects can overload binary operators (with no coercion) but it's not very common)
No parenthesis make nested calls unreadable? Simple add parenthesis for the inner calls. Like in any other language with optional parenthesis (Ruby) too.
Too long statements are unreadable? Don't write them. Maintaining an 80 or 100 character line limit is good coding practice anyways.
It's interesting how CoffeeScript fans almost always decide to blame the programmers for these problems. They said good developers should use common sense and use best practices to make code readable, for example by always using parentheses when calling functions. I hear exactly the same argument in the Perl community.
But reality is that if a language allows you to write bad code easily, people will write bad code, and you will have to read bad code. This is very easy to verify: most CS project on GitHub, starting with the CS code itself (http://github.com/jashkenas/coffee-script) contain a lot of bad ambuigous uses of the language. A very similar thing happens with Perl code.
Programming language design is not only about making it easy to write good code, but also about making it hard to write bad one.
a = 123 unless b == 2
"OK, so a is set to 123. Oh, unless b is 2. That's annoying"That said, my answer is to just not use the unless keyword. If you don't like CoffeeScript classes, you don't have to use them. IMO you could write CoffeeScript using only the kind of functionality availabie in vanilla JS and it would still be a preferable experience.
Of course, I've known Perl for 20 years, so that might have something to do with it. :-)
I find your code reads naturally enough forward. Your abstract brief example makes it no big deal to me which way round it goes.
One issue is "end weight". Let me slightly doctor the examples in http://perl.find-info.ru/perl/028/perlbp-chp-2-sect-16.html and ask you to compare:
When, after long nights of hacking, in horrible dreams there come to me damnèd souls responsible for ANSI C++, I run screaming.
with:
I run screaming when damnèd souls responsible for ANSI C++ come to me in horrible dreams, after long nights of hacking.
If I were writing one of the above two sentences, "end weight" consideration might lead me to write the latter.
If one applies these principles (left-to-right sweep and "end weight") to writing and reading of programming language statements one arrives at features such as the 'unless' keyword and the benefits they supposedly confer on writers (expressivity) and readers (ease-of-reading).
element.setValue value unless no_change
I'd read this example as: In most cases, we set the value of the element. However, sometimes there haven't been any chances, so there's no need to set any new value.Of course, I could write it as, for example
if change
element.setValue
but to me, however, although the end result is the same, that second example does not convey the same message to me as the first. In the second example, I'd interpret the normal situation as there being no change, but if there is one, update the element.I think that's also the reason why I like programming in ruby. I feel I am able to better express my understanding of the situation in code than I could if these seemingly syntactical sugary bits weren't there. I also think it is mostly a matter of personal preference.
I won't prejudge GorillaScript, but if someone ever makes a language like this that exhibits both good taste and a little more restraint, it could get wide adoption.
I don't really understand the ambiguity argument. From the code examples in the article, I get the impression that the author doesn't really understand CoffeeScript.
I definitely prefer CoffeeScript to good old JavaScript.
With no variable declaration keyword (a la var, my, local, private), adding a variable assignment anywhere could radically change the variable scoping.
I'm done, this isn't suitable for prime-time, time to go somewhere else.
I spent too many years in the 80s working with xBase. I've been shafted too many times by calling a (coworker's) routine that forgot to declare its variables "private", which stomped over one of my variables. (private in xBase is similar to local in Perl 4) To have a language which doesn't let you declare the intended scope of a variable - ugh.
More generally I've found that coffeescript mixes much better with a functional style than with an imperitive one.
Generally the same kinds of problems I find with bad ruby/java.
So does that mean Python and Ruby are out the window too? It's really never been an issue in either of the three languages.
changeValue = do ->
value = 42
lastValue = null
(newValue) ->
lastValue = value
value = newValue
That hides the new variables in a closure and they no longer leak to the the enclosing scope. This is cleaner code overall since you no longer have some variables at the top level where you can't be sure of how many functions are using them without searching.Now that I got my sarcasm out of the way, whenever somebody bashes CoffeeScripts variable shadowing they openly show the world that they don't understand how variable scoping should work. CoffeeScript covers up JavaScript's warts. One of those warts is JavaScript's broken implementation of closures. CoffeeScript is trying to help you, don't let your lack of understanding of lexical scope get in its way.
And that's what makes the whole line unreadable. And 'unless' would make it even less readable.
I can understand why people insist on discussing such personal, subjective matters as "readability" or "expressiveness" - I like that too. What I don't get is why do they confuse their impressions with facts and why do they try to generalise based on them. Is it that hard to admit that what's readable to you may be completely unintelligible to someone else?
Comparison of programming languages, outside of some really technical metrics, will always be subjective and preference-based. Discussing metrics as vague as "readability" without even agreeing on what it means is absolutely pointless. Yet so many man-hours go into debates and blog posts, sometimes even books, which cover such issues. It's stupid, straw-man discussion every single time it appears.
I really wish people would stop writing lengthy posts with a sole purpose of informing the world about their preferences. It's not that I'm against people having preferences, I'd just like them stated as preferences, not facts, and preferably only when they are not repeated a millionth time this month.
Edit: also, this: http://joelgrus.com/2013/12/24/why-programming-language-x-is...
> from the CoffeeScript tutorial...Furthermore, until you finish reading the line it isn’t clear which foods will be eaten.
The thing with typing the filter at the end is, that format has its basis in mathematical notation, particularly in set theory. Using an even terser mathematical syntax/notation, you could write the same expression this way:
{ eat(food) : ∀ food ∈ { foods } ^ food ≠ "chocolate" }
You read that as "the set of eat(food) where for all food in the set of foods, the food isn't chocolate". The notation will be quite familiar to mathematicians, and thus if you have a strong mathematical background, especially in set theory, discrete math, and combinatorics, the CoffeeScript array comprehension feels natural.See the Wikipedia article on Set-nuilder Notation/Set comprehension, http://en.wikipedia.org/wiki/Set_comprehension.
Here's another example from the Wikipedia article:
{ x | x ∈ R ^ x = x^2 }
This reads as "the set of all x, where x is a real number and x = x^2", which evaluates to the set { 0, 1 }. delayed: () ->
-> this.model # isn't the class
Well, that isn't really fair now, is it? You could have used the fat arrow (`=>`) for binding `this` to the class.With that in mind, I agree with the author in that CoffeeScript isn't the answer, at least not exactly. With syntax this incredibly similar, how far are we from compiling python (with generators, with statements, imports, ...) to JavaScript?
I frankly find CoffeeScript nicer than Python. There are advantages and disadvantages, obviously, but whenever I'm writing Python, it makes me long for CoffeeScript.
If you really get familiar with CoffeeScript then you will see that the benefits add up over JavaScript.
If you want a nice Python-like language with import statements and many interesting features that compiles to JavaScript, take a look at Nimrod.
func 5, {
event: -> 45,
val: 10}
Is reasonable but func 5, {
event: (e) ->
if e.something
36
else
45,
val: 10}
Really ought to be split up for readability no matter what programming language you use. And besides, the only issue is the extra comma causes it not to compile.To be fair, the `->` vs `=>` (which `this` is `this`?) for class members is confusing. I'd almost prefer class members didn't give you the option and defaulted to `=>`.
The "variable capture" section is overblown, though. You're a lot less likely to run into this issue than the classic JavaScript "I forgot `var` and now my variable is global.
My biggest complaint is actually the implicit returns. Sometimes I forget a return statement but it works anyway because of this feature. Then I come back later and modify the function slightly only to spend a bunch of time figuring out why it's returning `undefined`.
But since the author dismissed Dart due to not being "true to javascript", I doubt that he'd be satisfied with it
Anyone have a link to something from Rich mentioning why vectors are used in basic syntactic constructs? It's the one departure from its lisp roots that I couldn't figure out any motivation for.
I find that, having gotten used to the mental shortcut "square brackets == binding", the distinction makes it easier to read the "shape" of code from a very high level and get a general understanding of its meaning at a glance. YMMV.
However, this part I completely agree with:
> Realistically, the issues I have raised with CoffeeScript don’t come up every day. Ultimately though, they are enough to say we need something better. I hope to share some thoughts soon on what such a solution might look like.
CoffeeScript isn't perfect and we should always be looking for better solutions. So I'm glad that the author wants to add to the discussion. While CoffeeScript isn't the answer, it's probably the best answer we have so far,
I'll happily use coffeescript, and enjoy doing so, when that condition is met. It doesn't happen very often though.
I am biased towards Python and Ruby. I think that they are nice looking languages.
Different tools for different jobs. Next time I am on a JS project and I want to model data, I will probably use CS again.
How is JavaScript a minefield? Well, JavaScript has all sorts of pitfalls lurking for the developer. Each pitfall is like a mine in the minefield, silently waiting for you to accidentally step on it. Just like the minefield, JavaScript’s mines are hidden in plain sight. Entire books have been written about all the mines present in JavaScript. Maybe I’ll get into what some of those are in future blog posts.
So then he goes into why Typescript/Coffeescript/Dart aren't the answer to the "Javascript minefield" though he doesn't actually describe the mine's he's trying to avoid. He's not even bothering to setup a strawman to knock down. Its kind of hard for any tool to solve an undefined problem.
Given that a safe path through the JavaScript minefield isn’t enough, it seems like we need a detailed map of the minefield. Many books and blogs have been written to provide that map. JavaScript: The Definitive Guide by David Flanagan is one of the most detailed of those books. The JavaScript Garden is a good place to start learning about the mines online. [2]
[1] http://www.walkercoderanger.com/blog/2014/02/javascript-mine...
I like Perl, but I tended to be fairly pedantic with parenthesis and things when writing it. I prefer explicit over implicit. (Though sometimes implicit can save you a ton of time).
The absence of this feature is why me and Python don't get along.
http://johnkpaul.github.io/presentations/empirejs/javascript...
Not being able to import/include library code is bat-shit insane. You can't reliably check the type of things like arrays.
The 'this' value is 'wrong' in callbacks (by wrong, I mean, not what programmers actually need in that instance).
Javascript dates values are 1-based except for months which are zero based - be consistent!
Math.parseInt will produce correct results for 05, 06, 07, wrong results for 08, 09 - don't ASSUME a radix! (unless that radix is base 10).
It goes on regardless in the face of a large number of errors meaning that the location of an error can be much harder to find than is necessary - I believe that fail fast is infinitely superior to 'just muddle through and do something random with that invalid state'
You can't rely on getting decent stack traces out of it on error which makes debugging harder than it should be.
It's easy to accidently add globals.
I'd add lack of types: obviously that's a preference but when 30% of your tests just end up checking what a compiler could have done for you for free, then I say that;s a fault with the language.
That said, I really like array and object literals. It's not all bad. Just... about 86%
Gratuitously changing "function" to "->" for no reason other than removing characters seems to introduce more brand new idiosyncrasies than it's worth. If the goal were to improve JavaScript as a language by smoothing over a few of the gotchas, which of course would require a few syntax updates, then I think it would be immensely valuable. (Think SCSS instead of the original "Sass".) But it seems as if the authors were more troubled that JavaScript didn't write like Ruby, so they made a new language that happens to compile to JavaScript. And now I have two languages to choose from, each with pros and cons and their own gotchas, adding more complexity to my decisions when I was hoping for simplification.
What idiosynchrasies are you referring to here? Just curious. I love the stabby lambda (for the exact reason you listed, because I am defining functions on every other line).
Shortening it to two chars made sense IMHO. The long form of the word function directly impacts code quality and readability.
For what it's worth, the arrow syntax is likely going to be in JS at some point: https://mail.mozilla.org/pipermail/es-discuss/2012-March/021...
Shortening lambdas is one of the most important changes because it makes heavy callback/DSL code viable. Exhibit: http://coffeekup.org/.
Now renaming JS's `for (name in obj)` to `for name, val of obj` and redefining `in` to `for x in array` is indeed confusing (coming from other languages I can see how it's better than JS ideosyncratic use of `in` but still confusing...)
Let's say i want to start using closurescript,like coffeescript.
i want to do npm install -g closurescript then
closurescript compile myscript or closurescript myscript.
How do I do that?
If closurescript folks want their language to be popular with javascripters i need to be able to do that.
Right now,searching on google,on npm, i did not find any tutorial that did not involve maven or java.You cant expect a nodejs developper to learn maven or install the JVM for the sake of using clojurescript.
coffeescript is popular because it's easy to get started with.You dont even need to install anything,just add the coffeescript compiler to a HTML page.
Nevertheless, if this is all that keeps you away from clojurescript -- too bad. Because it is a great alternative to pure javascript.
http://coffeescript.org/#try:console.log%20%22hello%20world%...
For years I avoided using javascript beyond wiring little bits of jQuery together because I hated the language but eventually I ran into a project where I could no longer do that and resolved to learn javascript properly.
Many wtf's where had but now looking back I realise that Javascript is a warty language (but then show me a widely used (top 10) language that isn't).
I still don't like it but I don't hate it and I just accept it for what it is.
CS is not the silver bullet - but neither is blind believe that vanilla JS is the best way to code for the web. things change. technology runs in (hype)circles: we welcome the new stuff (i.e. languages), only we see the benefits of the old way, and then we still create new stuff...
Yes, a beginner might not see the flaws of Javascript up front, but given enough time to become an expert, they certainly will.