[Pitch] Allow trailing comma in tuples, arguments and if/guard/while conditions

I would appreciate this especially for cleaner git diffs as well as shuffling conditions around more easily.

3 Likes

There's no reason to disallow it. A single-element tuple is the same as the element alone.

3 Likes

Good example. If to choose between breaking compatibility slightly and introducing eliding commas vs not introducing eliding commas – I'd lean towards the former. BTW, we have a similar precedent with result builders:

@resultBuilder struct StringBuilder {
    static func buildBlock(_ parts: String...) -> String {
        parts.joined(separator: "\n")
    }
}
extension String {
    func foo() -> String { self }
    static func foo() -> String { "foo" }
}

@StringBuilder func case2() -> String {
    "hello"
    .foo() // ✅ treated as "hello".foo()
    "world"
} // same as above

@StringBuilder func case3() -> String {
    "hello"
    .foo(); // ✅ ditto but with explicit ";" to make it obvious
    "world";
} // same as above

@StringBuilder func case4() -> String {
    .foo() // 🛑 Reference to member 'foo' cannot be resolved without a contextual type
    "hello"
    "world"
} // same as above

func case5() -> [String] {[
    .foo(), // ✅ this is String.foo()
    "hello",
    "world",
]}

func case6() -> [String] {[
    "hello"
    .foo(),  // ✅ this is "hello".foo()
    "world",
]}

func case7() -> [String] {[
    "hello",
    .foo(),  // ✅ this is String.foo()
    "world",
]}

Note how it prohibits the .foo() form, even if that form is legit equivalent of String.foo() in other contexts.


As for the subject: +1 to the trailing commas.

4 Likes

Many languages allow trailing commas in more places than just array/list (/enum literals if they exist), Rust and Zig come to mind as being 'not less-safe languages' with liberal support of trailing commas. Maybe Kotlin too depending on your definition of less-safe?

  • Rust (a very safe language) supports trailing commas basically everywhere that commas are used (e.g. tuples, function parameters and arguments, struct definitions, enum cases, generic type parameters, and so on).
  • Zig seems to allow trailing commas basically everywhere since 2017 afaict
  • Kotlin allows trailing commas for function parameters and arguments in addition to arrays and lists
  • JavaScript also allows trailing commas basically everywhere, and although it's a less-safe language, it still adds to the precedent
5 Likes

If we wanted to minimize things that look like an error we could have a rule saying a trailing comma is only allowed as a line terminator. Therefore this could be a valid tuple:

(
   Float,
   Int, String,
)

while this would be disallowed:

(Float,
 Int, String,)

because the line doesn't end with a comma.

But it makes the rule more complicated, so there's a downside. Perhaps something to add to the alternatives considered section.

3 Likes

This doesn't look "an error" to me:

let x = (1, 2, /*3*/)
12 Likes

I feel like trailing commas only ‘look like’ errors to some people because they’re currently not part of the language, so they are errors.

In response to a similar statement earlier; in my experience, trailing commas never slow down skim reading or anything, at least if you’re used to them (I use Rust and JavaScript at work).

I feel like introducing a rule about trailing commas only being at the ends of lines would just make things more confusing. AFAIK there’s not a precedent for that in other languages, and it’d go against Swift’s existing trailing comma rules for array literals.

17 Likes

Perhaps in some cases or to some degree. The ability to get used to something isn't necessarily a good gauge of its merit, though.

I have experience with trailing comma support in other languages, and have seen them used in error (whereby the last element was erroneously omitted). Probably those errors would have been avoided if the compiler had complained about the trailing comma, although not necessarily (folks could still mistakenly just remove the comma).

I've also seen trailing commas left in not really as a deliberate choice but merely as an artefact of code changes. That they then end up used inconsistently within a given code base exacerbates their inherent ambiguity of intent.

As best I can recall, trailing commas don't usually indicate a mistake. But they sometimes require asking the question in code review, which is less efficient for all concerned than having the compiler ask the same question (i.e. by not permitting it).

1 Like

Agree with you, readability concerns trump things for me.

I would only be prone to concede this if they mandated Oxford comma everywhere in the language and the forums… (now I am joking and not joking in this last sentence).

It does to me; it looks like there is an item missing. Swift is more verbose than other languages for a good reason, readability at call site.

I really hope that style preferences are not used to shut down this proposal. It addresses a pain point in the daily task of writing code for many. I personally insist on using trailing commas in lists, and I really miss the ability in other areas of the code.

Like many other syntactic options and variations possible in Swift, if you don't like it, don't use it.

17 Likes

+1 from me.

For anyone who is opposed: convincing your own organization to add linting that forbids trailing commas seems like a much smaller and more easily-won battle than trying to convince the entire Swift community that no one should ever be allowed to use this type of trailing comma (emphasis on the fact that you’ve already got trailing commas to lint away and the core team already has precedent for permitting this coding style to those who prefer it).

7 Likes

+1, I like it. Improving diffs and copy'n'paste are enough reasons for me. Apart from a bunch of corner cases, it's purely additive, so if you don't like it, just don't use it.

7 Likes

While I am pro "trailing commas" feature, I must point out that the argument "if you don't like it, just don't use it" doesn't work, as "you don't like it" includes "you don't like seeing it when using/reviewing other people's code", in this case you simply can't "just don't use it".

5 Likes

We say that about literally every other feature that allows writing code in different ways. The argument holds weight when the change would force usage, but having to read it in someone else's code is not the same as using it in yours. If you're part of a collaborative effort, set standards. You should have them anyway, to litigate such things as the use of trailing closures or whether to omit return for single-expression methods or closures.

I am obviously unswayed by your argument, and I reiterate my hope that the language group feels the same.

5 Likes

Having worked at several companies with rigorous code standards, I"m all too aware how much engineering effort is lost arguing or manually reformatting. Witness also this thread. :slightly_smiling_face:

There is something to be said for languages which don't allow these arguments, whether by having a One True Format (e.g. Go) or by avoiding language features that are purely subjective or stylistic.

2 Likes

+1

  • Trailing commas make list manipulation easier and put equal level items on an equal footing. I'll stand by them being a more appropriate grammar for the context.

  • Trailing commas don't seem like they'd negatively impact reading speed and comprehension as there are other "end of list" indicators at play. I wouldn't be surprised if they increased it, honestly. (But of course that would be better confirmed with actual human factors testing, otherwise its all just conjecture)

  • They do not represent a change in code flow organization. It will not fundamentally change anything else about the surrounding code or code layout. The fundamental quality of the the logic code should remain unchanged with or without their usage.

9 Likes

For what it's worth, Go's One True Style mandates a trailing comma when there's a newline between the last element of a list and its closing delimiter.

10 Likes

Right, and I'm saying that's fine insofar as they made a universal choice. I personally think it's the wrong one in that specific detail, but the sheer amount of time saved from religious wars more than makes up for such small annoyances.

I'm not advocating for that approach with Swift, just observing the trade-offs.

I agree: if everything that touched format contention were verboten, there'd be no syntactic progress.

But I do think we should be cognizant of downstream problems this can solve, and users will be glad if swift-format et al anticipates and solves them, instead of lagging by months or more.

1 Like