`void` keyword (or dot, or bang, for no-arguments function calls) #514

Closed
sstephenson opened this Issue Jul 17, 2010 · 13 comments

Projects

None yet

8 participants

@sstephenson
Contributor

I'd like to open discussion for a void keyword, such that

x void

compiles to

x()

The idea came up in an IRC conversation about the dissonance of optional parentheses on function calls in cases like this:

if expression
  @pass()
else
  @fail message

In general, CoffeeScript style is to omit parentheses where possible. Omission is not possible for argument-less function calls. A void keyword could mitigate that:

if expression
  @pass void
else
  @fail message

I'm not convinced it's an improvement over @pass(). But maybe there's something here. Quoth jashkenas: "it's an interesting idea to have a keyword that has a presence like a variable in the language, but disappears before use."

@hen-zone

Worth noting that void is also a JS keyword. It's a unary operator which always returns undefined.

+1 for this idea!

@TrevorBurnham
Collaborator

My initial reactions to the idea were negative:

  1. If this is such a great idea, why doesn't Ruby do it? Oh wait—in Ruby, you can call x() by just writing x. Never mind.
  2. Ugh, CoffeeScript has so many "there's more than one way to do it" syntaxes: the boolean words, the choice of : or =... still, maybe one more can't hurt?
  3. If this becomes the canonical syntax, the verbosity will alienate a lot of people. x() is a familiar sight to programmers in just about every language.
  4. People are going to confuse x void and x null, no doubt about that.

But, then I looked at some of my parenthesis-cluttered code, and asked myself which is easier on the eyes:

if (x void and y void) or (a void and b c void)

or

if (x() and y()) or (a() and b(c()))

The latter is more succinct, but it takes a few seconds to figure out where the parentheses are used for breaking up the logic and where they're used for function calls.

Now, this problem could be solved with rainbow parentheses, but TextMate doesn't support that (to my knowledge). So, a hesitant +1. I don't think it should be the canonical syntax for calling a function without arguments, but I think it should be a valid alternative in case of parenthetical soup.

Update: sethaurus' comment above actually raises another concern. While void is rarely used, its meaning shouldn't change depending on whether it's being used for a function call or in another context. It's certainly an edge case, since the distinction between an undefined argument and no argument at all only matters if you're interacting with the arguments array, but it's still weird that you could potentially get different results from the statements x void and x (-> void)().

Here's an idea: What about using x . as the alternative syntax for x() instead? It's more succinct (same length as x(), so it won't even mess up spacing), and doesn't suffer from the aforementioned void ambiguity problem, or the potential for confusion with null.

This looks perfect to me:

if expression
  @pass .
else
  @fail message
@jashkenas
Owner

TrevorBurnham: This isn't directly related, but if you feel like there's already too much more-than-one-way-to-do-it syntax, it would be good to have a ticket that proposes getting rid of some of it.

I, for example, would be happy to use a CoffeeScript that only supported is, isnt, and :, and had no notion of ==, !=, and =. But that's just me, and it would certainly make it harder for new arrivals...

@jashkenas
Owner

For the record, we actually don't support the void unary operator at the moment. If you try to compile it, CoffeeScript will complain about it being a reserved word. I think that not supporting it is a feature -- it's a completely unnecessary part of JavaScript.

Can anyone think of an example where the traditional void is useful?

@TrevorBurnham
Collaborator

Ah, should've checked that—I think it's a good thing for CoffeeScript to not support the void unary operator. There are very rare occasions when I want to pass an undefined value (usually for testing); but that's not hard ([][0], for instance, or {}.a).

I'd like to repropose the x . syntax I mentioned in my edit above. I think it's a both more succinct and less potentially confusing than x void. Take a look at the three corresponding versions of the example I gave above:

if (x void and y void) or (a void and b c void)

if (x() and y()) or (a() and b(c()))

if (x . and y .) or (a . and b c .)

The last one looks pretty amazing to me. It's both the shortest and the clearest.

At first I was concerned about x.a and x . a having such different meanings, but the latter would be extremely rare—when was the last time you wrote x() a? Who returns a function from a function with no arguments, then immediately passes an argument to it?

In fact, I think that x . should become the recommended syntax for calling a function without arguments. (For consistency's sake, x(.) should be equivalent to x . as well.) What does everyone else think?

@weepy
weepy commented Jul 18, 2010

or you could have x!

@jashkenas
Owner

What do folks think about weepy's suggestion? It's not currently valid CoffeeScript syntax, and I think it's an interesting choice. I tried converting a sketch to use it, and it makes it very clear which banged-functions are called only for their side effects, and which functions are actually called for their value.

My main argument against it is that it makes CoffeeScript syntax more SHOUTY!, when I'm not sure that the mere fact of being side-effect-ful deserved all the connotations of an exclamation point...

@karl
karl commented Jul 22, 2010

I like both TrevorBurham's and weepy's suggestions, and would be happy with either.

The exclamation mark does come across as a little shouty, whereas the dot after the function name kind of looks like a typo at first glance, or that you are passing a single special parameter. But those are both minor points and I think both syntaxes are nicer than the current empty brackets.

Not a big fan of the void keyword, as at first glance it really does look like you are passing a parameter named void, it's not as clear that the function is being called with no arguments.

@gfodor
Contributor
gfodor commented Jul 22, 2010

I'm going to come down hard against using the bang. It's just asking to be abused, since really it should only be used for functions with side effects. For example:

if x! and y!
  # do something

Will be all over the place because it shaves off two characters, but breaks the universal contract for what bang should be used for.

Really, no matter how I slice it, I feel () should stay. There's not a pressing need to introduce new syntax for this particular case. The current syntax is clear, intentional, and short. The only real counterargument would be if there was a way to remove the need for ()'s altogether, but there's not, and arguably this would be a bad idea anyway since Javascript (being a functional language) is all about function application, and hence function calls should be explicit.

@TrevorBurnham
Collaborator

I don't like the bang syntax. As a JavaScripter, ! makes me think not. As a Rubyist, ! makes me think "this function changes something or raises an exception."

I think that support for x() should remain, but I really like x . Here's another example:

if (getTitle() is 'admin' or getName() is ownerName()) and not status() is -1 then welcome()
if (getTitle! is 'admin' or getName! is ownerName!) and not status! is -1 then welcome!
if (getTitle . is 'admin' or getName . is ownerName .) and not status . is -1 then welcome .

I find the third one to be by far the most readable; it's the "calmest," with very little punctuation.

@weepy
weepy commented Jul 22, 2010

javascript is not ruby and so i think we should allow somewhat free reign on the syntax without worrying about how other languages behave. I think the ! works, but we should certainly retain () support. I'm not a fan of the . as it looks like a property access

@jashkenas
Owner

I think gfodor's argument is persuasive. () mirrors calls that do have arguments, and mirrors parameter lists, purposefully. void, ., and ! have no such symmetry, and need extra explanation. We would leave the parens off if we could, but I'm afraid that's not in the bag.

Closing the ticket as a wontfix. If anyone comes up with an entirely new syntax for invoking functions, that they'd like to propose, we can re-open it.

@lzrski
lzrski commented Mar 7, 2016

Just a funny discovery - you can use backtics (embedded js) to call a function without arguments, without do keyword and without parens:

fn `` # backticks

It allows for (nice?) chaining:

fn = (args...) -> args.length

fn ``
  .toString ``
  .repeat 5

Above will give you nice '00000', as it compiles to:

fn().toString().repeat(5);
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment