SE-0257: Eliding commas from multiline expression lists

It is worth considering (I mention this, because it has been brought up in a previous comment) that no, Ruby, does not have comma-less parameter lists or array / hash literals. It does however have syntax shortcuts like the following:

%w(first second third) == ["first", "second", "third"]
%i(first second third) == [:first, :second, :third] # list of symbols

and a couple of similar shortcuts.

However, these are of a very different nature. Regardless of whether one believes that the complexity added is worth the benefit, at least one can argue that allowing people to omit commas and quotes (for strings) or colons (for symbols) has tangible benefits especially for people using Ruby for e.g. scripting; it just saves a lot of keystrokes. Furthermore, the scope of these declarations are very limited: it's immediately obvious that this special syntax will only apply within the scope of the %w()/%i() construction, so there should be no ambiguities.

By contrast, I simply do not see how a single comma between arguments / array elements makes a huge difference in terms of readability and I've certainly never considered it to be a "pain" in any way, no matter how DSL-y my code looks like. If anything, I would support special sugar for more specialised cases as in Ruby where the benefit is more striking and the context of this sugar is limited in scope.

Even if it didn't have any obvious downsides, I fail to see how this proposal is in any way addressing an actual problem within the Swift language (as opposed to some extremely subjective ideal about "code beauty"). The only argument I can see that I would personally attach any value to is the "minimizing diffs" one, but a) this could also be mitigated by allowing trailing commas (as mentioned several times) and b) let's be honest, git is a great tool and probably the best we have, but it kind of sucks at diffs anyway, because it has zero semantic information about the programming language, and there are 200 other things I wish git could indicate to me in a better way (e.g. when a method has been extracted) that routinely cause confusion in code reviews, that this minor nuisance is just really not that bad.

This coupled with the fact that it can cause real problems in some cases e.g. involving operators on the next line etc.ā€”which might not be a "problem" for the compiler but certainly can be one for developers who might fail to understand the error messagesā€”leads me to think that this feature does not fit in with the direction of Swift and would be a bad addition.

1 Like

FWIW, the precedent is Smalltalk, and especially ML family languages such as Haskell and Elm. All those use commaless argument lists, and the latter treat certain whitespace as a significant delimiter.

I suspect 80% of this unusually aggressive review thread ā€” all the opinions about whether commas help or hurt readability ā€” could be replaced by a poll that asks who is familiar enough with one of those existing no-comma languages to be used to looking at it. Which I suppose is fair: we don't want the language to feel too unfamiliar to its user base. (I tend to think half of why Java took off where other contemporaneous high-level OO languages didnā€™t is that it used curly braces.) Still, thereā€™s little use in arguing out rationalizations for familiarity bias.

(I don't mean to dismiss the concerns about confusing exceptions to the rule in func decls and .-prefixed expressions. Those are a different beast, not just a function of familiarity.)

4 Likes

I would be quite surprised if most folks who post on a Swift forum aren't at least somewhat familiar with Objective-C, which is also comma-less in its method calls.

The difference between Swift and the languages you cited is that those languages were explicitly designed from day one to be comma-less in those contexts, and thus don't suffer from the exceptions that many find problematic here. Since Swift was not designed to be comma-less originally, for many of us, the exceptions produced by trying to add it later in the language's evolutionā€”exceptions which arise in even simple cases, not pathological onesā€”don't justify the claimed benefits.

7 Likes

For function definition and application, sure. but Haskell still uses commas (or colons) for list, record, etc. separators. The same is true of Standard ML and OCaml (which uses semicolons for lists and records and commas for tuples). F# is the only ML based language I'm familiar with that allows for comma elision in multiline lists.

And it seems to me that one of the drivers for skipping commas, parens, etc. for function definition/application in those languages is the heavy use of currying and partial application which look more natural without delimited lists of arguments. Swift doesn't have a similar setup that makes comma delimited lists feel out of place.

1 Like

Hi Paul,

I'm familiar with several of those languages, and have used haskell extensively. It is interesting in that it never uses commas in argument lists, but does requires commas in list expressions. It doesn't have the behavior as described here of "sometimes needing commas, and sometimes not, inconsistently in different parts of the language".

Are you familiar with other languages that have a behavior as is proposed here where commas are sometimes required but sometimes optional in collection literals? Which ones?

-Chris

I'm -1 for multiple reasons:

  1. I don't agree with the premise that the colons are unnecessary noise.

  2. The point brought by @stephencelis and long discussion about applicability of colon elision in SwiftPM DSL is very convincing to me.

  3. I've got a feeling that a valid concern of the ambiguity of visually parsing closures in colon-less lists has become a hostage of current semicolon elision rules. While these two cases are similar on the parsing level, I do not think they're equivalent in the mental models of the programmers. The trailing closures might be an exception to some rules around newlines and semicolon, but for me, this was an exception introduces by a very good reason - to close the gap between how you write statements that introduce new scope and how you write expressions that take new scope. Bringing the same rules to the colon elision doesn't feel like closing any gap to me.

  4. For the semicolon elision, writing the code in a way that makes it visually parse quickly is a rare occurrence in my experience ā€” just because the most common way of calling

func twice(f: (Int) -> Int) -> Int { return 42 }

is either

twice { _ in 1 }

or

twice { _ in 
    1 
}

or

twice 
{ _ in 
  1 
}

and not

twice 
{ _ in 1 }

So, the common way in my opinion is either to either keep the opening of the closure on the same line or keep the opening and closing of the closure separate ā€” same rule as for writing if statement.

I think that in the cases that might benefit of comon elision the default is exactly reversed, bringing the ambiguity way more often to the programmer's mind. Which brings me to the final point:

  1. Using Swift extensively since first day of its public release, not once I've been surprised by any rule around semicolon elision. In the contrary, it took me almost no time to find the edge cases in colon elision. Might be that last 4,8 years are clouding my view, but I fear that this will cloud the view of many other current language users.

For all the heat it generated, nope, it's not that important imo.

I feel it does fit in the direction (it's a syntactic improvement to the language that helps its ergonomics), but not in the feel (Swift is leaning on the side of preventing the user from making mistakes like "goto fail" bug, and colon elision is increasing the possibility of such mistakes).

In the languages that I used and had something similar (Clojure) the rules of juxtaposition were so different then in Swift that I don't feel they are applicable.

Read the proposal, read the discussion thread, checked the pitch thread, did some playground experiments.

1 Like

As I wrote in the post you quote:

In other words, I do think inconsistency is a serious problem for this proposal.

5 Likes

I think we would all like it if everything just worked without commas. But the fact that it doesn't is not necessarily a reason to reject the proposal.

Everyone keeps comparing this proposal to semicolon elision. That makes some sense because there is an analogy with the newline replacing the separator. But it is not the only analogy. We also allow elision of parentheses in expressions. As with the current proposal this is something that is not always possible, even in relatively simple examples such as (a + b) * c. I haven't yet seen a convincing argument of why this proposal should be held to the bar of semicolon elision and not be considered more along the lines of parentheses elision, a feature which is also only usable in some (but not all) contexts.

Many of the folks commenting on this thread, including myself, specifically see the introduction of these inconsistencies as one of the fundamental problems here and have pointed out other solutions that actually remove inconsistencies instead (trailing commas). Respectfully, it sounds like you're trying to simply brush off the valid concerns and criticisms of many people in this thread as somehow being "not necessarily a reason to reject" the feature, and I don't see how that is terribly productive to the discussion. Should those of us who disagree simply not reply?

IMO, this is looking at it backwards, because it assumes that "parenthesis everywhere" are the default and "parenthesis elision" is the optional thing, when in fact it's the oppositeā€”"no parenthesis" is the default due to order of operations and "parenthesis introduction" is used to resolve ambiguity. Parentheses are used to group things to create a hierarchy; commas to separate items into a linear sequence. They're apples and oranges.

Order of mathematical operations and use of parentheses in mathematics has centuries of historical inertia behind it, and decades of inertia in programming. (Admittedly, this gets a little trickier with custom operators and precedence groups, but those don't typically occur to a significant enough degree that they're problematic.) Parentheses in this case are a historical inheritance of mathematical notation, not a completely new syntax being added to an existing language, and due to that history, a user who sees a + b * c should know precisely what it means and there are clear ways to explain when parenthesis would or would not be required. The removal of parenthesis in (a + b) * c isn't "parenthesis elision", it's "changing the mathematical meaning of the expression in a way that that has historical understanding."

This is not the same as the proposed comma elision, which does not have as strong a historical context and, even if it did, fails to work for Swift in even basic cases like arrays of enum cases or static member references because other syntactic constructs in the language were not designed to support it consistently.

12 Likes

It could be considered on that level, though there are differences there which lead to a stronger argument for paren elision than for comma elision.

For one thing parens have a much higher visual weight than do commas and are thus much more distracting to the eye. For another, you have the issue of paren matching, which does not exist for commas. Not only do you need to match count, but you need to make sure you have all of the parens in the correct locations to ensure the expression evaluates as intended. This is a much trickier proposal when you have the open and closing pair to manage than it is with just a single separator symbol. Finally, it seems (and I could well be wrong here), that historically, the goal has always been to minimize the use of parens, inserting them only where an expression is ambiguous without them (given the evaluation order of whatever system you're working in, natch), whereas lists of things often have some form of a separator, even where something like whitespace makes them unnecessary, e.g. bulleted or numbered lists.

Not at all, your reply is appreciated. What I meant here is that it is not a reason to reject the proposal out of hand without examining the facts. I did not mean that it isnā€™t possible for a reasonable person to think that in this situation the details lead them to a conclusion that it should not be accepted. And I certainly didnā€™t mean to imply that commenters on this thread are not considering the details. All I meant is that it is also possible to come to a different conclusion and it is not so crazy that some of us have.

Since this was pitched, I've been eager to offer motivating examples from folks like me who have experience with this formatting in other configuration languages. The strong opposition from @Chris_Lattner3 and others gave me pause to consider the effects and to request more discussion. I wish the pitch thread had been given more time to explore the ramifications. I feel the thread was shortchanged by some unfortunate passive-aggressive tension in some comments as well as dismissive attitudes that I hope can be forgiven as stress and misunderstandings. Sugar proposals like this can live or die on their own merits.

I'm pleased that the consequences of this change got to be hashed out here. I think the impact on transformation tools is a particularly strong point. I'm persuaded that there are enough nagging issues to make the benefits not worthwhile.

8 Likes

There do exist legitimate arguments against this proposal even if everything "just worked."

One, as touched on by @Ben_Cohen, is the contention that "we've gone beyond that point in the evolution of the language." It might be stated something like this:

  • The aesthetics of a programming language are an important part of its identity and its daily user experience (as reader and writer)
  • Now that Swift has been around for many years, users (and even non-users) have come to identify a certain aesthetic with Swift
  • Removing commas on a wide scale appreciably alters the language in a way that makes it no longer recognizably Swift--in others words, an appreciable number of users (and even non-users) may answer no to the review question: "Does this proposal fit well with the feel [...] of Swift?"

Now, to be clear, I agree with @Ben_Cohen that I don't think we are past the point of such a change. That is, I would like it if everything just worked without commas. But let's not ignore arguments to the contrary.

On this point, I do have to agree with others such as @Paul_Cantrell that inconsistency is a serious problem. I would go so far as to say that, in my view, it necessarily requires rejection of the proposal.

The reason isn't even with regard to the aesthetics of one or two items in a list having a comma and others not having a comma (which as mentioned can be solved with an all-or-none rule for each list). No: the reason that I think it necessarily requires rejection is that even some reviewers here specifically primed to think about this proposal mistakenly thought that they could elide commas from SwiftPM manifests and fell straight into one of the footguns.

I don't know that anyone thinks of the rules surrounding parentheses as "elision."

Moreover, rules surrounding parentheses with commonly used operators are taught in grade school to all children. And as we are all too aware, rules surrounding parentheses with operators not taught in grade school do cause problems, and Swift's rules do in fact require some additional parentheses not found in C/C++ by making some of these operators non-associative in an attempt to address this exact issue.

The proposed comma elision rules here are not taught in grade school to all children: therefore, if we were to make a comparison to the use of parentheses with operators, then the conclusion is that Swift should indeed make a best-effort attempt at not allowing elision.

10 Likes

There is a fundamental advantage with the leading dot syntax that you cannot fully match in a general expression context, no matter how smart code-completion is. The leading dot constrains the available options to only a handful of them, allowing not just helping complete what you type in a more focused manner but even to just browse and explore the available options. For a general expression context you could give higher priority to certain completion results but you are still dealing with a full unconstrained set of global symbols.

I'd like to make the observation that these quotes are a clear indication that comma-elision as proposed is significantly different than semicolon-elision, and has ramifications beyond being just syntactic sugar (no-one needs to spend time thinking about how to design APIs that can take advantage of semicolon-elision). This was not obvious to me before seeing the feedback here.

7 Likes
  • What is your evaluation of the proposal?

-1
I'd personally prefer to leave it as it is or choose an alternative which is to allow trailing comma. I find myself more annoyed with this limitation (not allowing trailing commas in parameter lists, but allowing it in arrays/dictionaries) rather than having to use a comma in the first place, which is so common that not using it feels not just alien but even a mistake, and can be actually a mistake or ambiguity when mixed with other language syntax and use of some operators and syntactic sugars like trailing closures or variadic argument lists.
The argument of trying to make EDSLs nicer in Swift IMO will lead to trying to make it fit with something else (what is already happening with an introduction of some other features) and as a result, we'll have a Frankenstein language.

  • Is the problem being addressed significant enough to warrant a change to Swift?

no, I don't see comma as a noise.
The choice of allowing to drop the comma rather than allowing trailing comma feels more like a personal code style preference rather than a serious argument for the change in basics of the language (same way as a preference of trailing comma is a personal preference, but that's not a suggestion that is being discussed)
Another question to ask - how would it fit if proposal about official Swift style guide will go through, what style will be preferred? This change would allow for more variations in the way people write code which does not help sharing it.
I also think that such experiments with basic grammar of the language, even if it is not breaking, should happen prior to 1.0 version, not at 5.0.
I don't know implementation details but I'd be surprised if this change would simplify implementation of the compiler, pretty sure it will become more complex.

  • Does this proposal fit well with the feel and direction of Swift?

unless the direction is to leave it with a bare minimum of punctuation, but then it will become some different language

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

not related to usage of a comma but in Ruby one does not have to always use parenthesis in a function call, which IMO creates ambiguity when reading the code and is asymmetric to the function declaration syntax where parenthesis are still required (AFAIK), unlike in Haskell. But I definitely would not use Haskell as an example of a language that is easy to read and understand, which is one of the selling points of Swift for people who starts to learn it. Adding another way of doing a simple thing does not improve this experience. I think Swift already has a balanced use of punctuation, which I also think is the most common one.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

a quick reading of proposal and this thread

4 Likes

I've been following this discussion for a while now and was rather ambivalent about this before, but this point puts me solidly in the negative. If this change affects API design, where some designs are more amenable to elision than others, that's not good for the language. I also don't think the comparison to semicolon elision is particularly apt, since semicolons were never about human readability, they were just an aid to the compiler. Commas are not.

So I can safely say I'm -1 on this proposal after reading the discussion threads and the proposal itself.

4 Likes

I'm pretty strongly -1 for the reasons others have mentioned. Possible confusion between things like - x and -x, and future limitations on the growth of the language. Writing a comma just isn't enough of a burden to justify it.

That said, I would be +1 on allowing a trailing comma...

On first reading the proposal I was quite enthusiastic about it, but having now read the entire thread here Iā€™ve changed my view to a strong -1. My main reason being the ambiguity it introduces as @hartbit explained in his post:

I could only be in favour of this change if it was something you never had to think about, either when reading or writing code. The comparison with semicolon elision has often been made, but in that case this condition is true: you literally never have to think about it.

Ambiguity makes code harder to read, and the language harder to learn. This proposal introduces JavaScript level quirks into the syntax of Swift that cannot be a good thing.

2 Likes

Strong -1, makes code harder to read

2 Likes

-1 for this proposal.

The benefits seem so small. I do not feel they at all make up for the many disadvantages I feel this would result in.

Commas, for me, are hints for parsing the language when reading it. Basically the whole premise of the proposal, that commas are visual clutter, is such a subjective statement which I personally do not agree with. The samples I have seen for comma elision seem harder for me to parse. Granted, it probably is just all about getting used to it. But I really wonder: Why? It makes things less consistent and more difficult for newcomers.

I really appreciate all the work done in the community regarding all this, and deeply respect all the discussion happening in this thread, by both proponents and opponents of this proposal. We all just want Swift to be more awesome. So do not see my -1 as in any way a critique of someone or something.

1 Like