5 ms·
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 syn
by thezilch 15y ago
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:
Declaring arrays
In CoffeeScript:
things_that_rule = [
"robot unicorns"
"honey badgers"
"Lord Inglip"
]
Destructuring assignment
Assign variables from inside arrays:
sum_and_difference = (a, b) -> [a + b, a - b]
[sum, difference] = sum_and_difference 5, 2
It's also bizarre from a Python background:
>>> [
... "a"
... "b"
... "c"
... ]
['abc']
=====
if foo.bar? then console.log foo.bar
# if (foo.bar != null) { ... }
versus
if(foo.bar){console.log(foo.bar);}
- shazow 15y agoI 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? [1] http://news.ycombinator.com/item?id=2542492 http://news.ycombinator.com/item?id=2542492
- guywithabike 15y agoHow often do you need a reference to a function and how often do you call functions in Ruby?
- grayrest 15y agoThe 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.
- arckiearc 15y agoI 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.
- shazow 15y agoPerhaps 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.
- antipax 15y agocall a function taking no arguments without using (): foo = do myfunction
- sunchild 15y agoI don't understand your swipe at Ruby. What's so terrible about: foo = object.method(:method_name) foo.call
- philjackson 15y agofoo = myfunction Considering the higher-order nature of Javascript programming having quick access to refs is important. The Coco dialect of Coffee suggests that a bang could be used to denote a call: foo = myfunction!
- grayrest 15y agoTo 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: $('.doAllTheThings').filter 'span' .data 'foo', true .wrap '<div/>' #produces filter('span'.data('foo' ... $('.doAllTheThings').filter('span') .data('foo', true) .wrap('<div/>') 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.add('myCoolModule', function(Y, name) { Y.CoolModel = Y.Base.create('coolModel', Y.Model, [], { aMethod: function(){return this.get('foo') === 1} },{ ATTRS: { foo: {value: 1}, bar: {value: 2, readOnly: true} } }) }, '1.0.0', { requires: ['app', 'model'] }); to: 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.