Allow trailing commas in parameter lists

Hello everybody,

as it was mentioned in this previous thread, I would like to bring forward again the request to allow trailing commas in function parameters.

Aim

The aim of this is to allow cleaner diffs when adding parameters in functions:

func makeUser(
       firstName: String,
+      lastName: String,
)

instead of

func makeUser(
-      firstName: String
+      firstName: String,
+      lastName: String
)

Reasoning

After the introduction of XCode 15's shortcut Refactor -> Format to Multiple Lines (control+M) we see that the automatic formatting given by Apple is with
) {
on the line after the last parameter.

The consideration

the core team does not want to encourage or endorse a coding style that puts the terminating right parenthesis on a line following the arguments to that call

given in the rejected thread doesn't seem to apply anymore, given the automatic formatting Apple now suggests.

What is your opinion on this?

Thank you

28 Likes

It's not often that language changes are proposed based on how git works, personally I don't think that's a good way to solve this, if you consider it an issue. It would be better to special case diff highlighting or something like that.

In addition, putting a separator at the end of a list feels contrary to all logic, even if it would often be more convenient. We have the same thing in the visual realm, few people want to see spacers or dividers at the end of a list, even if it's much messier to get them to show only between elements, in say a ForEach-VStack in SwiftUI.

2 Likes

A trailing comma is already allowed in array and dictionary literals - do you see this as fundamentally different from that, or do you see that as having been a mistake?

15 Likes

I do really dislike that, and it's of course fairly similar, but I feel this is even worse, since function signatures are defined in a closed, specific form, unlike arrays, which are more of a "format".

Also, a general objection is that the superfluous comma looks absurd when the function is written on a single line, so do we want to have different rules for different whitespacing (would be a first I think) or allow something as hideous as this:

let angle = atan2(a, b,)

2 Likes

The thing is, it’s not only useful with respect to the diff, but it is also hugely convenient when re-ordering parameters, both in the function signature and at the call site, so to me the risk of someone I work with writing the clearly ugly code in your example does not nearly outweigh the reduction in friction in my daily workflow.

Also note that with the newly implemented variadic generics I think the gap between collection literals and parameter lists has been reduced.

8 Likes

This is not unprecedented:

{print("atan2"); atan2(a, b);}
[1, 2, 3,]

Personally I'd consider removing all that punctuation noise from everywhere, be it on a single line or on multiple lines.

1 Like

Reordering parameters definitely feels like it should be solved by tooling, which would be trivial to do. Then that could also cover the single line case, which this language change would not. Well unless people started using the hideous form…

This is a proposal that was formally reviewed and rejected by the core team; reconsideration would require some substantial new insight or change to the language since that time, and nothing has fundamentally changed about function declarations.

Xcode is not Swift, and nothing from the core team or language steering group has superseded the prior statement that does not encourage or endorse the coding style mentioned.

6 Likes

I guess since variadic parameters already existed at the time of the rejection, variadic generics don’t count as a fundamental change in this area? Also I think trailing commas in collection literals also weren’t available at the time of rejection - that also doesn’t count?

The core team in 2016 said that it

does not want to encourage or endorse a coding style that puts the terminating right parenthesis on a line following the arguments to that call

while now automatic indentation of parameters by XCode does exactly that, that's why I reopened the request. It seems to me that there has been a change

4 Likes

I'm not sure how: no new use of any punctuation—commas or otherwise—was introduced by variadic generics.

It was: it's mentioned in the very top of the rejection.

Oh, sorry.

Fair enough - I’ve gotten by this far while tolerating the friction of swapping commas around while changing the order of parameters and I’m sure I can carry on forever more without too much pain.

Ah, it occurs to me you're referring to call sites: it's a good point that with variadic generics there are function calls that we didn't have before.

We've always had the most common of all functions that accept a variable number of arguments though—print—and it didn't sway the core team, so :man_shrugging:

3 Likes

The text from the core team refers to arguments (i.e., at the call site); it's also the weakest and last of the reasons given.

Moreover, even if Xcode ships with some other choice to the automatic formatter [edit: which it does, as I see that call sites are also formatted with a dangling parenthesis], it shouldn't be taken to supersede the core team's explicit decision.

2 Likes

Understood thank you @xwu :pray:

That would be ideal, but we don't control the entire programming biosphere.

Sure Apple could special-case this in Xcode's diff view, but there's also every other editor, file differ, including online platforms like GitLab, GitHub and such.

If they haven't all already addressed this for more popular languages, there's no shot the world will change any time soon for Swift.

3 Likes

An alternative solution to the diff / line-reordering issues is to let newlines function as commas, as SE-257: Eliding commas from multiline expression lists proposed. That solves that problem and reduces unnecessary visual noise from superfluous punctuation.

Alas, it was rejected - although, without prejudice, so it could be re-pitched. Though, it's not clear to me from reading the [long] review thread what exactly the review committee felt needed addressing.

5 Likes

i’ve found that lack of trailing commas tends to confuse GitHub Copilot, which did not exist in 2016.

i don’t think it’s realistic to change how git works to accomodate the swift language.

6 Likes

I wasn't a member of the core team at the time, and I'm speaking in my personal capacity, and I am generally wary of review decision relitigation but... I think this is a case of a decision that is worth revisiting, even in the absence of something changing, on the basis that the rejection justification reason is fairly weak.

Funnily enough, that weakness shows up also in the motivation given in the OP of this thread. Minimizing diffs does indeed not seem enough of a justification. I've also seen arguments that this helps with code generation, and that also seems insufficient.

The reason I wish Swift had this feature – a reason I bump into often, maybe even daily – is that I often find myself commenting out the last line in a tuple or argument list (at call or def site). When working with code, I find myself doing this very frequently, and whenever I hit this problem I am frustrated by the inconsistency with collection literals. Instead of just sticking a // (via a keyboard shortcut) at the start of the last entry, I must either edit the line, or weave around the new line with /* */, or adopt some formatting hack like putting the commas after the new lines.

Here is an example I hit today. I was experimenting with the performance difference using a 3-tuple vs a 4-tuple to represent a 3-dimensional vector:

    var velocity = Vector(
        1.66007664274403694e-03 * DAYS_PER_YEAR,
        7.69901118419740425e-03 * DAYS_PER_YEAR,
        -6.90460016972063023e-05  * DAYS_PER_YEAR,
//      0
    )

By contrast, if I had been using SIMD types, which are initialized with array literal syntax, this would not have been a problem. And of course, I comment in and out collection elements all the time too.

It is possible I'm just a weird case, and the kind of code fiddling I tend to do means this happens to me more than other programmers, and so it's not enough reason to add this feature. But I don't think so.

Perhaps the introduction of variadic generics and APIs such as SwiftUI has altered the nature of Swift being written these days. Or perhaps what has changed is that just more real-world swift code is being written than in 2016 less than 2 years after Swift was introduced, and so what I experience myself fairly frequently might strike a chord with the now very large number of developers who work with Swift daily.

Finally, the reason:

Finally, the core team does not want to encourage or endorse a coding style that puts the terminating right parenthesis on a line following the arguments to that call.

is very mysterious to me, since doing this was already the adopted style of the Swift standard library codebase, when lines exceed 80 chars. It has since also been adopted as the standard style in both Xcode and swift-format. While none of these (except maybe the style used in the std lib, at least for swift committers) is "official", I do think they're a indication that an (unexplained) opposition to them was not a good justification for this part of the argument.

42 Likes

One thing that has potentially changed that might make it worth revisiting is the introduction of macros. Since macros must generate ASTs that are syntactically correct when rendered back as Swift source code to be sent across the wire to the compiler, there's non-zero overhead required to put trailing commas exactly where they need to be in order to generate a valid AST. Either users have to manage that themselves by checking for the last element, or swift-syntax has to implement the logic to take a list of things and put the trailing commas in the right place (some of the advanced syntax builder APIs may already do this).

Granted, trailing commas aren't the only place where syntactic bits have to be carefully audited when writing a macro, but simplifying them so that users can just say "always add a trailing comma when constructing this node" would I think be a concrete win in that domain.

13 Likes