To be fair, one shouldn't bash Brendan, he had to build the initial JavaScript language in a week[1]. It's not his fault the language became the defacto web-language.
Yes, if there's one thing that Doug Crockford should have taught us all by now, it's that Brendan was actually pretty smart, and we were damn lucky to end up with Javascript compared to what could have been.
I don't know.... If it was really bad, it could have been replaced with something better. If it was really good it could be kept. Today we're stuck with something half bad/half good, we're keeping it and it is uncomfortable at times.
Add it to the deficiencies of html and css and web dev becomes a chore.
I found that whole part of the presentation to be a real turn off. All those guys (beards or not) deserve admiration. Any one who creates a language that's used by hundreds of thousands of developers probably did far more right than they did wrong.
I understand it was just a stupid joke but when your stupid joke insults a person who deserves praise you should probably reconsider the joke.
Oh, I'm absolutely not trying to bash Brendan. The fact that he managed to produce anything at all in the short time he had is profoundly impressive on its own, and the core of genius that exists in between the Bad Parts is worthy of all kinds of admiration. Also, the way I understand it, he originally intended to make a Scheme implementation for the browser - unsuccessfully, alas, but it still suggests he may well be the most amazing man in web history, even if he does know how to use a razor.
The point of the JS bashing in the slides is that the Bad Parts do exist, and CoffeeScript does a great job of routing around them, as does Strict Mode.
I don't understand why this is downvoted. Does somebody disagree? Why?
It's true, every time I see CoffeeScript vs JavaScript examples, they're often unfair. Some addressed in this older thread[1].
Another thing I don't understand is why make the parenthesis for function calls optional? Such as
sum_and_difference 5, 2
Especially since one of the most common complaints about JavaScript is ambiguous inconsistency (var, semicolons).
Ok, so parenthesis are optional,
foo = myfunction()
calls myfunction, but
foo = myfunction
does not? I suppose this is better than the way Ruby does it where you have to jump through hoops to get a reference to your function, but is this really better than making parenthesis for calls mandatory?
The optional parens is something I personally go back and forth on. I went through a phase where I always left them off but have been moving back towards using them most of the time. The holdout is for calling things that take functional arguments. Here's how I'd write the nodejs.org home page example:
{createServer} = require 'http'
host = '127.0.0.1'
port = 1337
server = createServer (req, res) ->
res.writeHead(200, 'Content-Type': 'text/plain')
res.end('Hello World\n')
server.listen(host, port)
console.log "Server running at http://#{host}:#{port}/"
Notice `require` looks sort of like a language statement. The `console.log` thing is my own quirk. However, the call to `createServer` would require a hanging paren if parens weren't optional. It wouldn't look bad here (and, in fact the official example uses it to chain the listen call) but is less attractive if you're using longer functions. Calls like `memoize` and `operation` (think unit of work pattern) tend to work well with this.
Perhaps I'm crazy but I honestly feel mandatory parenthesis here improve readability
{createServer} = require 'http'
{createServer} = require('http')
console.log "Server running at http://#{host}:#{port}/"
console.log("Server running at http://#{host}:#{port}/")
At the very least, it improves consistency which to me improves readability. Making something "look like language" (or perhaps "prose" is more appropriate) doesn't improve the parsing process for my brain. In fact, the inconsistency with the rest of the non-language "code" throws it off the tracks.
Even if it didn't, I'd still say the ambiguity is not worth it. Perhaps CoffeeScript needs a "use strict"; for the final stroke of irony.
One more question: Why "#{foo}"?
Is there any template language that uses this syntax? (I am not familiar with one.) If it were up to me, I would have chosen "${foo}" to be like Mako, or plain "{foo}" to be like Python's string formatter, or "{{foo}}" to be like the more recently popular Mustache.
Edit: As cschep points out, the "#{foo}" syntax is Ruby string formatting syntax. Thanks.
I went through the same process as you. I think it's okay not to have hard and fast rules for every acceptable situation to leave off parentheses, it's more a judgement call based on the readability of the statement.
`Require` and `console.log` are perfect examples where leaving off the parentheses helps with clarity, same with the call to `createServer`. In your example I'd even argue that you could do the same with `res.end` too.
To me the most convenient thing about it is the auto-declaring variables and proper loops. Whether the sugar is worth it or not comes down to taste. I used Python as my primary language from 2001-2007 before switching to Javascript/Coffeescript full time so I'll provide a bit of commentary.
> Arrays could use a beard or the varied language syntax is going to cause ingrown pains
The whitespace magic only causes me a problem in a few situations.
Watch indent on wrapped if statement:
if foo is true or bar is false or
baz is null
doSomething() #Error
if foo is true or bar is false or
baz is null
doSomething() #ok
Explicitly returning objects is awkward:
foo: ->
if not ok then return
#lots of code here
return
x: 1 #ha ha
y: 2
foo: ->
if not ok then return
#lots of code here
return {
x: 1 #ok but ugly
y: 2}
I always want to use implicit call parens with property chaining but that doesn't work:
The result of assigning a comprehension threw me off for a while because I was thinking Python list comprehension instead of postfix loop:
foo = x + 1 for x in array
foo = (x + 1 for x in array) #what I expected
(foo = x + 1) for x in array #what happens
for x in array #same thing written the other way
foo = x + 1
Finally, the whitespace magic working well tends to depend on object/functional arguments coming last in the call list with the functional arg coming after the object.
These annoyances are relatively rare and are the sort of thing you just get used to if you use the language heavily. The upside is that for an appropriately designed API (the options object argument last convention in JS makes this fairly common), the object literal magic gives a feel like python kwargs:
animatedShow node, duration: 200, onComplete: -> fire 'doThing'
You can also do DSLish things fairly easily. I'm a fairly heavy YUI user. Compare:
YUI.module 'myCoolModule',
version: '1.0.0'
requires: ['app', 'model']
(Y) ->
Y.CoolModel = CoolModel
class CoolModel extends Y.Model
@ATTRS:
foo:
value: 1
bar:
value: 2
readOnly: true
aMethod: -> @get('foo') is 1
It requires a one word patch on Coffeescript (superclass name in generated output) and the addition of a tiny YUI.module to YUI.add shim but I think the result is a lot cleaner.
> It's also bizarre from a Python background
Python's auto-concatenation of runs of string literals is convenient but I don't know of another language that does the same thing.
> if foo.bar? then console.log foo.bar
The ? is an explicit existence check, while doing `if(foo.bar)` will fail if bar is an empty string or zero. I tend to write existence checks using the postfix form:
console.log foo.bar if foo.bar
This is a personal style that indicates that the normal control flow is to log but there's a simple guard on the operation. I'd use the if...then form if I expected the test to fail a significant fraction of the time (i.e. it's a branch instead of a guard). My other quirk is that I use &&/|| only for short circuiting but and/or only for boolean logic.
I'm not going to fight on most of the non-parenthetical aspects of the syntax -- it always sounds like a holy war, everyone is right, and everyone is wrong.
I've not looked closely at the implementation, but Python concatenating adjacent strings might be a relic of C-based languages -- the same rule applies there and likely a standard of the language with CPython being the default underbelly of Python.
Then your final (YUI) example, we have "random" commas. Again, the language syntax starts to trend towards generally inconsistent, and I have to enforce more style guides upon my team.
NOTE: I work heavily with YUI as well, and my team -- Python stack -- too writes shims to support "kwargs"-like syntax, so I can't really consider coffeescript having an advantage. Quick pseudo comparison...
The random comma in the yui example can be eliminated fairly easily. It being there is due to Coffeescript not being able to support the following call style when I initially wrote the shim.
YUI.module = function(o, f) {
var name = o.name,
ver = o.version;
delete o.name;
delete o.version;
if(!name || !version) throw "Both `name` and `version` are required.";
return YUI.add(name, f, ver, o);
}
YUI.module
name: 'myCoolModule'
version: 1.0
requires: ['app','model']
(Y) -> ...
Ultimately CoffeeScript is syntax sugar for Javascript that you pay for with wrong line numbers when debugging. I think it's worth it, but I have friends who disagree. My coffeescript source is about 30% fewer lines of code than the equivalent javascript. Roughly half of that is entirely closing braces/parens but the other half is actual code reduction/simplification, mostly from loop comprehensions.
I also use it for API design. My habit when doing the design is to write out code for how I'd like to use it. I always use coffeescript for this regardless of whether I'm implementing it in JS or CS because a bad api visually looks bad to me when I write it out and I bang at it until it looks right. I've been mocked for this process by a couple people who have asked for my input on their projects but I've never had someone not take my resulting recommendations.
is starting to look close to unreadable and overcompressed (in particular, the constructor implicitly declaring member variables).
Also having a quick look through the bug reports, there seems to be some interesting inconsistencies, such as:
x for x in [1,2,3]
# x == 3
x for x in [1..3]
# x == 4
I also see a complaint that:
foo bar: 'baz', quux('onoz')
Won't parse. I understand this should parse as:
foo({bar:'baz'}, quux('onoz'))
Both of these, and other little things I've seen, make me think coffeescript is more of a giant bag of good ideas, rather than a well-thought out language. In particular, is there a clear unambiguous grammar for it anywhere? I can't find one.
> there seems to be some interesting inconsistencies
Yeah, there are. These bug me less now than they did initially. Like any language, you have to know it well to use it well. But there's much less that you need to know about CoffeeScript than about, say, Ruby or Python. CoffeeScript's feature set is small enough that you can master it very quickly.
> is there a clear unambiguous grammar for it anywhere?
> Out of interest, how does coffeescript scale, and can it start to get unreadable?
It works well enough if your API design fits the language's expectations. This generally means your function calls take arguments in the order: normal args, onlyOneObject, callback.
How well it scales is sort of a taste question. I like that getters/setters and some event handlers tend to be one line. Here's a pair of functions I actually wrote today (I'm building a proprietary wysiwyg text editor that isn't using contentEditable)
getBlocks: -> @_breakText(block.get('value'), block.getLineBreaks()) for block in @blocks
getSelection: -> try start: @input.selectionStart, end: @input.selectionEnd
Here's a random longer function:
_getWords: ->
if @words.length
@words
else
@_doWrap()
words = []
pos = 0
size = 0
Y.all(@wrapSelector).each (el) ->
size = el.get('text').length
pos += size
r = el.get 'region'
words.push el: el
size: size
pos: pos
top: r.top
left: r.left
right: r.right
bottom: r.bottom
@words = words
You'll either think these are neat or that they're horrible. Note that the first is a comprehension and the second is a try/catch block returning an object (it can fail in some older gecko browsers if the page is still loading).
> in particular, the constructor implicitly declaring member variables
I think this is excessively cute as well and don't use it. Nor do I use the `x = {a, b}` producing `x = {a:a, b:b}` trick, which causes problems with implicit object parsing when the object isn't the last argument to the function.
> In particular, is there a clear unambiguous grammar for it anywhere? I can't find one.
There is not and there probably won't ever be. Doing one would be complicated quite a bit by the rewriting pass that happens before the compiler starts working on the code. A grammar for the resulting, unambiguous code wouldn't be too hard but that comes from the rewriter handling most of the hard corner cases.
I'm curious, would you prefer to write code like this over the explicit version?
foo bar: 'baz', quux('onoz')
Or are you just concerned about inconsistencies?
I like not having to specify parentheses, but only do so when it's immediately obvious to a reader of the code what the result of the statement will be.
My concern (as something thinking about trying coffeescript) is that it takes me quite a lot of mental effort to parse that, and at the moment the compiler seem to have trouble with it. I'm wondering if it practice it becomes more natural as time progresses.
Much of your difficulty/effort is due to lack of familiarity. The rule is basically if you see an identifier followed by a space, it's a function call that ends with the line, outdent, or postfix control flow statement. An identifier followed by a colon means an object literal.
I have no more trouble recognizing these patterns than distinguishing between function calls and parens being used for grouping. Part of that is due to my own enthusiastic syntax highlighting for vim [1] that leaves identifiers as pretty much the only piece of text not highlighted. If you take a look at that file, the syntax in it is very old and comes from when : was the assignment operator which was dropped when implicit object literals were introduced.
I agree, other than a few operators there's nothing new here, it's just bits of ruby/py etc combined basically (the object stuff looks like yaml :) haha, kinda fun), and as you mention it looks great in small snippets, but gets really unwieldy in practice from what I've seen.
I will never understand how you dislike coffeescript so much. Even if you only use it to stop having to type }); and the word function, it's worth it. Everything else is a bonus. Tried it on a real project?
I hope this submission doesn't signal an era of meme-worship here on Hacker News. "Fail" may just be borderline, but it sure triggers my radar.
The flood of memes slid slowly in the back-door at reddit, one innocent step at a time. Questioning this often got you the comment that you were old, stiff and lacked the funny-gene. Time passed and look at what a worthless trollhole reddit eventually became.
I hope to see fewer submissions like this on HN in the future.
Does anyone else prefer the syntax of javascript to that of coffee script? Really, my only problems with javascript are no multi-line strings and type coercion (but type coercion issues are mitigated by always using ===). Otherwise, I think javascript is a fine language. Also, the with statement isn't that bad in my opinion.
I'm with you on that one. The only thing I feel that really needs improvement in javascript is the long-winded lambda syntax, seeing as they're used so much. Everything else I'm perfectly fine with. Honestly, most of what coffeescript brings is fewer keystrokes, at the cost of ambiguity. I don't see the purpose.
And I'm sorry, but whitespace-for-blocks really kills it for me. I can't stand it in python, but I'll suffer through it for the ecosystem. Coffeescript brings nothing to the table for me.
Significant whitespace is a big turn off for me too. What you gain in concision for small examples you more than lose in tooling and code manipulation.
I used the think the exact same thing. However, after spending some time with tools that do consider white space significant (coffeescript, haml, sass) I have come to prefer it. It's part noise reduction and part consistency between devs and environments that I prefer.
Because you can't automatically re-indent code. In a language like C or Javascript, I can just copy, paste and move chunks of code around and have pristine re-indentation with a keypress. In Haskell, Python, or Coffeescript I have to be very careful and have to manually re-indent if I want to move code or change scopes.
Whitespace is much better left as a purely aesthetic feature, IMO.
I like the fact that there's a very low-barrier to entry of trying out the language while you're learning about it. This makes the material "stick" much better than just arrow-keying through a presentation.
I agree that the interaction could be better, though.
I think JavaScript gets many things right, but has an overly verbose syntax. So CoffeeScript hits a sweet spot by adding syntactic sugar while hewing close to the underlying language.
You and Alanis Morissette may call that ironic. I'd call it practical.
Perhaps I'm missing the point here, but I don't get why there's such a hype over CoffeeScript. People seem to prefer learning a brand new language in order to avoid getting proficient in another language they already (should) know.
Or in other words, people prefer to learn a language that will code another language for them. Its like I'll go and learn Japanese just so I can use it to write phonetic English.
In the case of CoffeeScript, the appeal, in my mind, is that it's _not_ a brand new language, it's just an improved syntax and some extra language features over what is essentially plain old JavaScript. Anyone who already grasps the fundamental concepts of JavaScript can master CoffeeScript in a matter of hours. Of course, the syntax is a matter of taste, and one might prefer something like JavaScript 1.8, which comes with the same new language features as CoffeeScript, and more. But some of us (and I suspect we come mostly from Python and Ruby) prefer the concise syntax of CoffeeScript over all those curly braces and semicolons.
Well, its true the syntax of CoffeeScript is trivial, and coming from Python background myself I find it very easy to comprehend. But I also find Javascript fairly easy to work with and to be honest I rather work on my target language without the abstraction of another (at least in the case of JavaScript). Take the javascript issues covered in the presentation - they are not hard to work with as long as you treat them as part of the Javascript package (for example, var your local variables to make them local. not hard to make into a habit).
The beard slide made me laugh, but it doesn't hold any water. Ryan Dahl is clean-shaven in the node.js intro video on their website. Also, I think Javascript is great. Its 'bloated' syntax makes for minimize-able files which can end up being half the size of the originals. That's just a preference thing.
Maybe I misunderstood, but he said Coffescript's significant indentation solves Javascript's bloated syntax. I was just saying that code that uses significant indentation can't be minimized, as JS files often are.
http://bodil.github.com/coffeescript/#compress-slide
Doesn't matter either way. If you are in a production environment, using coffee-script would almost always involve a one-time compilation step to minified JS.
If you are sending real users coffee-script over the wire you are wasting a lot of their attention.
That was funny yes. I also loved the slideshow itself. I wonder if it's written in CoffeeScript? If so, that really shows that you can make really cool things like this (interactive, cool effects, and even with code interpreters) in CoffeeScript.
Sorry if I'm late to the game but I have to say I started using vim-coffeescript with coffeecompile on watch mode and it's wonderful. It's basically like the window on the homepage but in vim.
[1]http://www.jwz.org/blog/2010/10/every-day-i-learn-something-...