I don't understand what problem is being addressed by this holistic “solution.” Swift today supports passing multiple closures and using trailing closure syntax. Only one closure can be “trailing;” it's the one at the end of the argument list. The other ones don't trail, so they don't use trailing closure syntax. This is by design, at least for some of us who were involved in the design.
I'd like to elaborate just a little more on why the current design is good and why the proposal is bad for the language, then I'll be done here.
Trailing closure syntax leverages “code shape recognition” instincts formed by the precedent of common built-in constructs like for
loops, where the body, which is part of the loop, “hangs off the end,” of the construct rather than being nested inside it. That position at the end is a recognizable, uncluttered, place of privilege; it signals to the reader that it's the main part, and if there are braces in other parts of the construct, they tend to get nested inside parentheses:
for x in (a.lazy.map { $0.aspect }) {
theBody()
}
(a.lazy.map { $0.aspect }).forEach {
theBody()
}
Extensible constructs like if
/else
and do
/catch
, with multiple braced parts, are recognized as a chain of these little patterns, rather than as one big unit, so are analogous to chained method calls:
if_(someCondition) {
clause1()
}
.elseif_(nextCondition) {
clause2()
}
.else_ {
clause3()
}
Sometimes the conditions/patterns in these constructs involve secondary expressions with braces. As with for
, these secondary expressions don't move to the end of the unit just because they involve braces:
if (a.contains { $0 < 0 }) {
clause1()
}
else if (a.contains { $0 % 2 == 0 }) {
clause2()
}
else {
clause3()
}
The one exception to this rule is repeat
/while
, which is extremely rare in practice and in my experience reads very poorly when the condition involves a closure, because it clashes with expectations set by the rest of the language.
These proposals suggest that the main/body part of function calls that take multiple closures should no longer be at the end, but somewhere in the middle. There are at least two problems with that:
- That position is inconsistent with the precedent set by language features, which will make it harder to recognize patterns in the code.
- Independently of any precedent, that position, “buried” in the interior of the function call expression, with a label and another closure following it, is objectively less prominent.