I understand how existing syntax encourages removing the argument label from the first trailing closure rather than the final trailing closure, but I'm worried that this puts us at odds with APIs designed for pre-Swift-5 code, which would put the "heaviest" closure last and "light" ones in the middle in order to make existing trailing closure syntax feel natural. I admit I don't have any real-world examples of such API, but there's a reason for that beyond trailing closure syntax: the "heaviest" closure is the one that likely goes on the longest, and you wouldn't want to have to scroll past it to see that there are more arguments.
Section {
List(…) {
HStack(…) {
// may go on for many lines
}
}
} header: {
...
} footer: {
...
}
(sorry for the straw example; I don't do SwiftUI very much.)
On a more nebulous note, it also feels weird to me that all of these are the same call:
foo(bar: { provideBar() }, baz: { provideBaz() }, garply: { provideGarply() })
foo(bar: { provideBar() }, baz: { provideBaz() }) {
provideGarply()
}
foo(bar: { provideBar() }) {
provideBaz()
} garply: {
provideGarply()
}
foo() {
provideBar()
} baz: {
provideBaz()
} garply: {
provideGarply()
}
Which argument label is omitted is completely up to the call site. I've been a proponent of trailing closures for a long time, and pushed back against people who complain about the last argument label being omitted, but this gets to a point that makes me uneasy, though I can't quite pin down why. (Usually I'm the one who says "people can write bad code in any language".)
I'm sure this was already discussed, but I'd be much more comfortable with "all trailing closures take an argument label; if there is exactly one trailing closure, the argument label may be omitted".
foo() bar: {
provideBar()
} baz: {
provideBaz()
} garply: {
provideGarply()
}
Slightly odd-looking? Perhaps. But it keeps the name omission part from being coupled to the ordering part, and I think that's potentially useful when the rule for name omission isn't just "the final argument label".