- What is your evaluation of the proposal?
Enthusiastic +1 with some suggestions below.
- Is the problem being addressed significant enough to warrant a change to Swift?
Yes. Here's why:
Trailing closures look good and @dabrahams described it well. 'Trailing closure syntax leverages "code shape recognition" instincts formed by [some precedents]'.
But more than that, I argue that adjacent braces and parentheses, or braces within parentheses, are generally confusing and appear out-of-place.
It's somewhat true when inline: foo({ ... })
, but more clearly true for this:
foo({
....
})
Braces indicate structure, parentheses grouping, but here it looks like parentheses are also getting in on the structure game. Even moreso this, with the straggling close parenthesis:
foo(banana: 5, action: {
...
},
additionally: {
...
}
)
(IMO this is ugly too: var foo = { ... }()
, but that's for another day).
Trailing single closures work well to increase visual simplicity, but yes, for functions with multiple closure parameters it's problematic. And it will remain a thorn in the language if something like this proposal isn't adopted.
Also, I don't think it's been a good thing how the best practices for ordering optional parameters are set aside so that the desired closure parameter can take the precious final spot, as others have mentioned.
- Does this proposal fit well with the feel and direction of Swift?
Largely. Earlier versions of the proposal have not, and I would never have used the feature in code I was to write. Only with the modified proposal for this second review have I been on board.
I strongly feel that code like this looks good, and is most consistent with the single trailing closure case:
foo(banana: 5) {
...
} additionally: {
...
}
I endorse the direction the proposal set as far as best practices for placement and naming of closure arguments.
However, given the valid concerns about cases like Binding(get:, set:)
, situations of ambiguity, and what seems to be individual style, I think it's better to permit the more awkward looking case where the first closure parameter is also named, and for the choice to belong to the writer of the calling code.
I do think it looks better when the function includes the open-close parentheses foo() action: { ... }
as opposed to foo action: { ... }
but I think that should be up to the writer, unless there are parsing issues precluding the latter.
I think it might potentially be suitable to have less common cases where the API writer decides this instead using some new attribute, maybe in cases like Binding(get:, set:)
.
What I don't like is the accumulation of possible trailing closure combinations, some having unfortunate results.
In place of calling code the API writer intends:
foo(banana: false) {
...
} additionally: {
...
} optionally: {
...
}
also permitting this code which lets the wrong closure parameter be un-named seems wrong to me:
foo(banana: false, action: {
...
}) {
...
}
If considering breaking source compatibility for Swift 6, I think it could make sense if trailing closures were either all or nothing. Meaning the first trailing closure parameter has to be the first of the closure arguments in question, and if it's provided within the parentheses then they all have to be.
Or perhaps instead of making that a hard requirement, have it a clear style recommendation, because I haven't considered all implications of default values.
Regarding the idea:
If a trailing closure argument is declared with a label, it must be specified, regardless of its position (i.e., including the first)
this goes against what we have already and strikes me as fiendish consistency over practicality.
Sacrificing visual cleanliness for simpler rules doesn't seem like a good trade off. I don't think new users will benefit from logical consistency for this, as I think the proposal has a visual consistency that's intuitive. Also it will encourage more parameters without labels which is bad for when not using trailing closure syntax.
- If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
No
- How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
Glanced at earlier incarnations of this pitch, proposal, and discussions. Read this latest proposal and this review thread thoroughly.