-
-
Save jashkenas/1790643 to your computer and use it in GitHub Desktop.
# Apart from the basic niceties of being able to leave off | |
# parens in clear calls... | |
print 10 | |
alert "Hello #{name}" | |
# ... the reason why they're important to have in CoffeeScript | |
# is because it allows our "block" syntax (single function body | |
# passed as the final argument to a call) to play nicely with | |
# significant whitespace: | |
fs.readFile "config/options.json", (err, contents) -> | |
... work with file here. | |
# Writing the above without the ability to leave off the | |
# parens which would otherwise have to wrap the function body | |
# would defeat a large part of the purpose of significant | |
# whitespace in the first place. |
I wound up putting explicit parens around the click((e) -> ....)
to avoid this false differentiation, which suspect will annoy conventional CoffeeScripters.
If the point is to avoid the trailing delimiter on blocks, I would much prefer a syntax based on HEREDOCs. Something like this:
$('some_selector).click( (e) ->>)
...anon function contents go here...
This is comparable (but more concise) to a Perl or Ruby HEREDOC:
foo(...).bar(<<END)
blah blah text goes here
END
Since CS has significant whitespace it can eschew the explicit delimiter. In effect this:
$('some_selector).click( (e) ->>)
...anon function contents go here...
Would say to me "the following indented block gets inserted -->here<--", without mis-cueing me that there is something special about that function call.
It is immaterial, in the sense that you can choose to write calls-with-anon-functions-as-arguments with parentheses or without in every case... Note that this is not true about Ruby.
object.call { |e|
...
}
object.call &proc
object.call(&proc)
# If you try to be consistent:
irb(main):002:0> [1,2,3].each({|i| print i})
SyntaxError: compile error
Your suggestion is interesting:
$('some_selector).click( (e) ->>)
... contents ...
... but unfortunately from a readability perspective, it doesn't hold water because you're very clearly closing the parentheses, and thus the call, before the contents of the call exist. Mis-nesting parentheses with special syntax to indicate a placeholder for where their arguments will be inserted is a direction I don't think we should take.
I will also make the general observation that when you want to let programmers use fewer parens (a noble goal), it seems easier to accomplish using Smalltalk-style method calling than using C++/Javas/Ruby/etc-style dot-calling. Dot-calling and removing parens are syntactical principles somewhat at odds with each other.
In your Ruby example you appear to be conflating anonymous function syntax (which in Ruby 1.9 is ->(args){...}) with block arguments. CoffeeScript doesn't have block arguments so they shouldn't enter the conversation. The Ruby equivalent to your example is:
[1,2,3].each(->(i){print i})
Which is perfectly valid, although not how #each
is defined to be called.
My question is: how else can I make the calls in my first example visually consistent? Is there some way I can also leave out the parens around the $('some_selector')
part?
In my Ruby example, I'm pointing out that Ruby has to have a special case for the syntax we're talking about here, one which doesn't behave consistently with passing a function expression as an argument... We can talk about the same Ruby inconsistencies with other block forms:
puts(if true
5
else
10
end)
# => 5
puts if true
5
else
10
end
# => syntax error, unexpected kELSE, expecting $end
Whereas in CoffeeScript:
console.log( if true
5
else
10
)
# => 5
console.log if true
5
else
10
# => 5
... but in any case, to answer your question -- if you value visual consistency for that call, I'd recommend either of these two options:
callback = (e) ->
... code ...
$('some_selector).click(callback)
# Or:
$('some_selector).click( (e) ->
... code ...
)
... both of which work fine.
If you don't like the HEREDOC-inspired syntax (understandable; that form of HEREDOC wigs a lot of people out), how about this. An alternate method-call syntax with very low binding priority. I'll use ..
for the sake of example:
$ 'some_selector' .. click (e) ->
...click handler...
The latter of your two examples is what I used, but I share your distaste for the trailing paren in a language that tries to avoid them. The former is obvious but not really helpful, since I'm looking for syntactical fixes, not code restructurings. What do you think of a low-precedence method calling syntax for chaining without parens?
Ah, interesting. An explicit "close" operator that ends implicit calls, without having to start them... That would be great material for a Github ticket, if you feel like writing it up and starting discussion. I also don't think it's something we've ever talked about before (a true rarity for CoffeeScript syntax proposals).
Another way to avoid the inconsistency is of course:
($ 'some selector').click (e) ->
...
The example which drove me batty was:
Which instantly signaled to my programmer brain: there is something special about the function
$()
, since it is called with parens andclick()
is not. And I didn't know what was special about it, and that is always troubling.It turns out that there is nothing special about it; except where it appears.This really bothers me, because it's signaling a difference where there is no difference. Both are functions taking arguments; the fact that one happens to take an anonymous function argument should be immaterial to how it is called.