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.
Comments
Every time I'm left unconvinced, either by pointy-edged syntax or not fair representations of javascript...
Arrays could use a beard or the varied language syntax is going to cause ingrown pains:
It's also bizarre from a Python background: ===== versusI 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
Especially since one of the most common complaints about JavaScript is ambiguous inconsistency (var, semicolons).Ok, so parenthesis are optional,
calls myfunction, but 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?[1] http://news.ycombinator.com/item?id=2542492
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:
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
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.
Ruby does string formatting that way.
Jade is a templating lib for javascript, and it uses #{var} and !{var}.
(Although I don't know what that would be doing in a console log.)
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.
I don't understand your swipe at Ruby. What's so terrible about:
foo = object.method(:method_name)
foo.call
The Coco dialect of Coffee suggests that a bang could be used to denote a call:
How often do you need a reference to a function and how often do you call functions in Ruby?
call a function taking no arguments without using ():
foo = do myfunction
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:
Explicitly returning objects is awkward: 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: 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:
You can also do DSLish things fairly easily. I'm a fairly heavy YUI user. Compare: to: 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:
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.> Python's auto-concatenation of runs of string literals is convenient but I don't know of another language that does the same thing.
The C preprocessor (in GCC and Clang at least) will concatenate adjacent literals, so add C, C++, and Objective-C to your list.
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.
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.
> Roughly half of that is entirely closing braces/parens...
This is good, as it improves the code's readability.
> ...but the other half is actual code reduction/simplification, mostly from loop comprehensions.
This may not be good, as it can reduce the code's readability. List comprehension should only be used moderately, else you will end up with this:
http://blog.garlicsim.org/post/3504711416/nastiest-python-li...
Also, with python, at least you gain performance advantage by using list comprehension.