Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternate Form for Parentheses #1614

Closed
benekastah opened this issue Aug 18, 2011 · 13 comments
Closed

Alternate Form for Parentheses #1614

benekastah opened this issue Aug 18, 2011 · 13 comments

Comments

@benekastah
Copy link

In Haskell there is the $ operator which helps you avoid parentheses. I think this is great because it would establish readability without having to worry about marking the beginning and the end of a parenthetical grouping (inasmuch as it can be inferred correctly with the slightly more limited $ operator).

A few examples:

# normal
fn1 fn2(a, b, c, d, fn3(e, f))

# alternative
fn1 fn2 $ a, b, c, d, fn3 $ e, f
# or
fn1 $ fn2 a, b, c, d, $ fn3 e, f

In this case, the rule is that wherever you would put an opening paren, you simply put a $ instead. The closing parens will be inserted at the end of the line. I believe this is the way Haskell does it.

An interesting alternative would be to put the $ in the place of the closing paren instead. This way, you could insert them as you realize you need them a little bit easier. It may also be more handy to interrupt the normal parenthesizing process for custom behaviors. This would require a different example:

# normal
fn1 fn2(a, b, c, d), fn3(e, f)

# alternative
fn1 fn2 a, b, c, d $, fn3 e, f
# or -- comma placement is different
fn1 fn2 a, b, c, d, $ fn3 e, f
@michaelficarra
Copy link
Collaborator

One major setback with this proposal is that $ is a valid javascript (and hence coffeescript) identifier. Not only valid, but actually in quite common use, as many popular libraries provide it as a short reference to their namespace. So the syntax would definitely have to change.

As for the idea: it's one of those features I absolutely love about Haskell but I'm not really sure whether it's appropriate for coffeescript. A simple explanation of my understanding of the $ operator: insert an implicit set of parentheses from here to the end of the line. That's an extremely common case in Haskell, but not quite as much in coffeescript. So I'd be really interested in seeing some pros and cons of this operator as well as a usable syntax.

You might be interested in #1429 as well.

@jashkenas
Copy link
Owner

Just to throw a quick reaction in here, this syntax is fascinating, but strikes me as horrifically unreadable. The beauty of parens in nested method calls is that they're the same way you'd group things in English, as well as in Math.

The best way to write this seems to be:

fn1(fn2(a, b, c, d, fn3(e, f)))

... or better yet, with local variables.

@cognominal
Copy link

I love the $ in haskell.
The motto is : prefer chaining to grouping

Once you have many operators at different precedences, you have to use parenthesis,
No clean way around it. I have a book about the history of math notations, And I think I remember
other approaches like shifting vertically inner operands. This results in a waste of vertical space
of would not work on ttys.

But it is ok to invent syntax for very common operators.

But, because of many toolkits using method chaining, method calls are more common than function application in coffeescript. I would like a low precedence method call operator to avoid parenthesing the method call parameters.
If I understand well the . method call operator is very high precedence (bind a lot) which precludes that.

Let's take an example from http://geekiriki.blogspot.com/2010/08/jquery-meets-coffeescript.html
The author is "just amazed how brilliant jQuery and CoffeeScript are working together."
Not so much. Let's note the author has done a lot defensive parenthesizing but this is related to the
problem I state. In doubt, he parenthesizes every method call. Note that $ is here the jquery identifier.

show_message = (msg) ->
   $('#message').hide().text(msg).fadeIn(2222,
      -> $('#message').append('!')
 )

Anyway, to be fair, the example can be written

  show_message = (msg) ->
     $('#message').hide().text(msg).fadeIn 2222,    -> $('#message').append '!'

Using the -.- as low precedence . operator, we get

show_message = (msg) ->
   $ '#message'  -.-  hide().text msg -.-  fadeIn 2222,   -> $ '#message' -.- append '!'

This is not shorter in term of characters count, but that suppress the parentheses clutter
and clearly separates the different chunks that are method chained while conducing the
sight to the next chunk. (just like serifs do in typesetting). Note the $ in haskell has the opposite
approach, it is shorter so it does not separate chunks by distance by the vertical barrier of the dollar bar.

-> seen as an operator bind less then .-.
Parentheses are needed for the hide method, so as not to be interpreted as a property so we don't
gain here to follow it by a -.-

I suppose you can combine method chaining with fonction application. I suppose that functionsapplication
would bind less and would need a longer operator like -..-
Not sure we need it is as much than an alternative operator for method calling

@paulmillr
Copy link

Function calls in haskell don't have commas. And the language itself has currying.

I don't think that function application would be a great idea for coffee script, if there will be no built-in currying and 'comma-less syntax'.
More "real world" haskell function declaration, that is actually readable:

genOutput number = return $ concat $ mapMaybe numberToValue [1..number]

vs

genOutput number = return(concat(mapMaybe numberToValue [1..number]))

@michaelficarra
Copy link
Collaborator

@paulmillr: "currying", as in the mathematician Haskell Curry.

@paulmillr
Copy link

@michaelficarra sorry, just a typo. fixed.

@michaelficarra
Copy link
Collaborator

@paulmillr: sorry, didn't mean to nitpick a typo, but it was made twice (and they were identical), so I thought you might rather be educated.

@benekastah
Copy link
Author

@michaelficarra -- Yes, I wasn't actually thinking we should use the $. It's just the only symbol I could think of for the purposes of demonstration. That said, coming up with a good symbol for it would be tricky.

@jashkenas was thinking that this would be pretty unreadable, and @paulmillr had a good point that the $ operator plays to the strengths of haskell better than it plays to the strengths of coffeescript. I also think that haskell's precise implementation of this wouldn't be a perfect fit for coffeescript as it stands.

@cognominal's idea on using something like this for chaining function calls without having to use parens stood out to me as a great example of where parentheses could be eliminated in both a practical and useful way. I don't know if -.- is the exact operator I'd pick, though. Maybe something more like:

$ '#message' &.hide().text msg &.fadeIn 2222, -> $ '#message' &.append '!'

The rationale for the & sign being that the word "and" in English seems to terminate a phrase in order to add a related phrase, so in this code it would indicate that the last grouping is terminated and we are now appending something related (in the form of a chained function call).

As for the readability of this snippet, I'm not totally sure. I suppose that because it isn't natural for us to see this we immediately brand it as "unreadable" (I admit it doesn't seem terribly readable to me). The successful use of a similar operator in haskell, however, seems to indicate that it would be readable if we were used to it. Looking at that, I think I could get used to it, providing the line isn't too long. A snippet like this would be more readable:

"asdf".replace "a", 0
&.replace "s", 1
&.replace "d", 2
&.replace "f", 3

Thoughts?

@michaelficarra
Copy link
Collaborator

I just remembered #1407. I think it's very related. #1495 and #1251 are also somewhat related.

@cognominal
Copy link

@benekastah I am very open on the choice of the alternative method call operator (MCO) name. My point is that the visual aspect of it matters very much. Also my comparaison with the $ was to show that one can go to totally opposite direction in this visual choice. I chose -.- because it contains a dot like the standard MCO and its length is a hint at the low binding. May be three characters is going overboard. So -. would be enough. -.- being symmetric hints at a commutativity that does not exist.

But I like &. even more. The & is visual reminder that somethings stands before that is handled by that operator. The -.- is in fact five characters because it needs space around to stand out when &. does not so we got 2 chars vers 5.

@paulmillr I agree that $ (or whatever token chosen) works better with haskell syntax.

@goomtrex
Copy link

Howdy. This is related to #1520, except this:

fn1 fn2 <- a, b, c, d, fn3 <- e, f

Will currently produce this:

fn1(fn2(a, b, c, d, fn3)(e, f))

But I reckon I'll probably make it more like what you are suggesting:

fn1 fn2(a, b, c, d, fn3(e, f))

@goomtrex
Copy link

I have made this change, and it's actually more consistent (read: correct) with respect to the indented syntax:

f <- x, y <- z

Is the same as:

f <-
  x
  y <- z

And:

f(x, y(z))

@benekastah
Copy link
Author

@alexkg looks interesting! I'll have to try out your branch soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants