satyr/coco

Change the auto-return hushing syntax to a literal !->

Opened this issue · 11 comments

Whenever I start out with a hushed function

thing.onclick !-> console.log \clicked

And then want to add a parameter, I usually end up doing this:

thing.onclick (e) !-> console.log \clicked e

Which, unlike (e) -> ...., actually compiles to:

thing.onclick(e(function(){
  console.log('clicked', e);
}));

This is--given how auto-return hushing works--how that code should compile, but I'd much rather it compile to what I expected, and I've been bitten enough times by it to care.

Proposal

Let the literal !-> define a function without auto-return:

<arglist> !-> <fn body>

In the same way -> defines auto-returned functions.

Why

I think of !-> as analogous to the ruby convention of appending ! to functions that mutate in place, e.g. array.uniq!; !-> defines functions that usually change state, not return values.

But since !-> is really not ->, a hushed function with arguments becomes !(args) ->, which loses most of that distinction.

Using the english form of hushing also reads really strangely:

thing.onclick not -> console.log \click
not function doStuff => do stuff

With a literal !-> marking hushed functions instead, there's no chance of a confusing-looking not being used, nor is there a break in muscle memory when changing -> it.stuff to (thing) -> thing.stuff or !-> it.method! to (thing) !-> thing.method!.

For named functions, the literal function! could be used unambiguously:

function! mutate-stuff a b c
  ...

Furthermore, this change doesn't have to immediately break backwards compatability, since not <fn literal> still would otherwise evaluate to a useless false. The old hushing method could be deprecated while still introducing the new hushing literals.

Other thought is that the literal could instead be !>, but that loses the distinctive arrow look of regular ->.

I believe it was made for this kind of case : get-fn! ->.

What does get-fn! -> signify? I don't see how that effects the proposal.

gkz commented

get-fn returns a function, which is then called with the parameter ->

I understood that part, but nothing about that effects hushing auto-return.

get-fn! !->

is still unambiguous.

Needs {up,down}-votes.

Other thought is that the literal could instead be !>

That leaves out ~> and <~. See #91.

Avoiding symbol-bikeshed was one of the reasons to choose the current syntax.

That leaves out ~> and <~. See #91.

True, which is another reason I didn't like !> as much. Promoting !-> to a single token is less of a bike-shed problem, given that it's already in wide use as two symbols.

More succinctly, here are my arguments for a literal !->:

  • !-> already looks like a standalone symbol and it's used plenty of places in the coco source--as well as my own projects.
  • unlike @prop or &method, !-> is entirely made up of special symbols, so it's harder to recognize that it is, in fact, two symbols (as a comparison, haskell makes all-symbol identifiers auto-inflix).
  • Adding arguments to a hushed function doesn't feel the same as a non-hushed function, since the optional arglist is actually squeezed between the ! and the -> instead of in a space, e.g. fn = -> it => fn = (arg) -> arg.
  • Having ! <fn literal> hush the auto-return is a clever way to make compilation simple, but given that nobody really uses the english not form, I think it's clear that human coders aren't thinking not ->, they're thinking !->. See also: not function and <- not expression.
  • Recognizing !-> as a standalone literal is backwards compatible, and given its widespread usage (as two symbols), much of the code that has hushed functions wouldn't be deprecated either.

And the full list of changes are:

  • !-> <body>: hushed function symbol.
  • !~> <body>: hushed bound-this symbol.
  • <-! <expression>: hushed backcall symbol.
  • function! <args> => <body>: hushed function literal.

I'm actually less sure about function!. !function would be more backwards-compatible (if only in how it looks), but function! is more english-like or ruby-like.

Not sure about function! as well, but +1 for unified !->

akx commented

👍 for unified !-> and why not function! too. Don't see anything wrong with that.

!-> would put ! just before the actual function syntax (->). !function already works that way.

gkz commented

I support this, though I feel it should be !function rather than function!