From my perspective, it's largely a misuse of the syntax to only pop out of the parenthesis an arbitrary subset of the trailing closures. I think it would be a mistake for us to weight this consideration too heavily.
The API guidelines emphasize clarity at the point of use, in particular:
When evaluating a design, reading a declaration is seldom sufficient; always examine a use case to make sure it looks clear in context.
I think it's important to go one step further and focus on "real-world" (or at least "realistic") uses cases. The striking thing about the APIs I found in my research was that they tended to have a "primary" closure, which didn't require an argument label in order to be clear (at least in my opinion):
UIView.animate(withDuration: 0.3) {
self.view.alpha = 0
} completion: { _ in
self.view.removeFromSuperview()
}
Props to @ricketson who was the first one (AFAIK) who observed this. An animations argument label would be totally redundant:
UIView.animate(withDuration: 0.3) animations: {
self.view.alpha = 0
} completion: { _ in
self.view.removeFromSuperview()
}
... making it a violation of the API naming guidelines:
- Omit needless words. Every word in a name should convey salient information at the use site.
Combine has an unlabeled sink variant:
ipAddressPublisher
.sink { identity in
self.hostnames.insert(identity.hostname!)
}
... and SwiftUI has an unlabeled Section variant:
Section {
// content
}
The authors of these APIs established names and conventions to make the role of these closures clear without a label. Appending additional labeled closures does nothing to make the initial unlabeled closure less clear.
I see the appeal of the order of the closures matching the vertical display order for SwiftUI's Section. Whenever possible we tried to craft the SwiftUI APIs to evoke the UIs they represented and this is in keeping with that.
However, I'm wary of us over-fitting to SwiftUI's Section use case. It's my intuition that, most of the time, the label on the first closure would just be a "needless" word.
ipAddressPublisher
.sink { identity in
self.hostnames.insert(identity.hostname!)
}
ipAddressPublisher
.sink receiveValue: { identity in
self.hostnames.insert(identity.hostname!)
} receiveCompletion: { completion in
// handle error
}