[Accepted] SE-0279: Multiple Trailing Closures

I think the consensus is that the change is too small. It doesn't extend far enough. It (somewhat?) works if you have one primary closure and a bunch of secondary ones, and you can arrange the primary one to occur first. Other configurations, especially co-equal closures, don't work as well. Worse, the approved change requires more en masse method renaming than the suggested change. (And if we do extend from the approved change to the suggested change later on, it would create more churn from undoing the first set of renaming.)

1 Like

No it does not. No renamings are being made through this proposal. The only thing that is changing is the API guidelines. This should not be taken to imply that the guidelines will or even should be applied retrospectively, other than through further evolution proposals that would be considered individually.

Additionally, this new guideline does not ban labels on closures (leading to an implied need to mass rename), but rather recommends that APIs be designed “assuming that the argument label of the first trailing closure will be dropped”. This has always been good advice for trailing closures, since a label that does not assume this can end up being highly misleading, as is the case with drop(while:). But a label that can be dropped without losing clarity is not in conflict with this guidance. Of course, there is plenty of room for interpretation since clarity is subjective. But that is a matter for future proposals.

5 Likes

I believe @CTMacUser is referring to existing APIs which would need to be reworked, not to comply with the naming guidelines, but the fact that Xcode's default behavior will now be the new syntax which wasn't in mind when the APIs were designed. Existing usage will continue to compile, but new usage will not be readable. And in any event, there are many examples where API designers can't comply with the new guidelines, even if they wanted to, just as there were with the original trailing syntax. So many designs will just look bad with the new syntax and there's nothing the author can do about it.

It's clear that there's no room to maneuver here, so I guess the next step is the updating of style guides and formatters to recommend against the new syntax in certain scenarios, similar to how the original syntax wasn't recommended when using multiple closure parameters. It would be great if Xcode 12 integrated swift-format to give us some control here, but I doubt it.

7 Likes

This justification seems very odd to me.

Without mass renaming, existing functions like drop(while:) won't go anywhere. The problem of semantic obscurity still remains for those functions. So, the new guideline doesn't help existing APIs.

At the same time, the new guideline doesn't help new APIs, either. If not for the mandatory omission of the first label, then there will be no need of (whether implicitly or explicitly) “assuming that the argument label of the first trailing closure will be dropped”. The new guideline massively restricts API design, when the alternative solution would have set it free.

The guideline change and the multiple trailing closures go hand in hand forming a circular logic. This whole thing is like writing a Wikipedia article that cites its source from a New York Times article, which in turn cites its source from the same Wikipedia article.

1 Like

drop(while:) is one of very few (maybe the only) API that is unambiguously misnamed in the standard library. So the idea that "mass" renaming is required to address it is incorrect.

API design of single closures have always been restricted in this way. It has always been poor Swift API design to requires the closure label to make the call site clear. To some extent the API guideline change was a "ride along" – a minor addition the core team agrees is worthwhile given the existing situation with trailing closures. Perhaps it would have been better done as a separate proposal to avoid confusion.

An alternative solution to SE-0279 would not have done this. A different proposal, addressing single trailing closures, may have. SE-0279 being accepted does not significantly change whether such a proposal can still happen, for both single and now multiple trailing closures, as John pointed out at the start of this thread.

3 Likes

I seem to somehow misunderstand this. Can you elaborate why this is an implication of the acceptance of this proposal? The guideline itself MUST go through an evolution pitch/review phase and not just be changed at will to support another proposal. I think this would be an unfair change if it was just implied from here.

1 Like

Please, please tell me that this proposal and it’s adoption are not the product of secret motivations known only inside Apple? That mistake was made last year, and ought not be repeated.

[I wrote that comment after reading the first 40 posts in this thread. Now, I've read them all. In retrospect, I'll write a new post that better expressed my intent.]

1 Like

Thanks for clarifying that, Ben. I actually misread the resolution somehow as including changes to the standard library.

2 Likes

Dear Swift,

I offer this humble reflection:

It seems to me that externally facing argument labels represent an extremely useful ergonomic affordance for people. Specifically, they add nothing to the formal or mathematical expressibility of functions, which require only an unambiguous list of symbols to represent lambda abstraction.

However, upon being offered the option of a labelling facility, many people will endeavour to use such labels to express meaning. As soon as they do, that meaning will accompany the annotated function everywhere it goes, carrying this meaning with it in a fashion which hopefully makes similar sense to other people.

Importantly, from that point on, if ever those labels are lost, the intended meaning (to people) will be lost.

Because labels are optional affordances, and add verbosity to function names, it seems tempting to think that this loss of meaning can at times be borne without undue cost. The cost benefit-analysis in an environment (formal languages) which traditionally favour succinctness, frequently says, 'yes', this will be ok. In particular, the likelihood that the formal part of the language will 'break' is very small. The program will most likely continue to work in any case.

However, it seems that, in practice, the burden of this loss of meaning upon people is not insignificant. There is a strong sense that such meaning is after all important, and the loss is perhaps felt more significantly than was presumed.

For this reason, it seems to me that the inclusion of labels in a language demands a degree of consistency which is not currently exhibited by Swift.

Once introduced as a concept, any and all functions, whatever the 'context', really should offer labels. Labels should always need to be explicitly omitted when the author does not need or wish to use the extra level of meaning which labelling affords (this explicit exclusion could continue to be inferred when arguments themselves are inferred).

Upon consistently carrying labels, no mechanism should remove a label when one exists. One must suppose that the author's intended meaning will always remain significant to people using the function, as an aid in determining which arguments they should supply.

Without this supposition, and the corresponding ubiquity of labels' appearance in whatever context their function appears, labels remain a promising but ultimately compromised aid to written comprehension.

Clearly, there exist historical and technical impediments to such expectations being met in Swift (and obviously other languages). It may never be possible to achieve consistency in this regard, especially if the balancing interests of source compatibility and/or brevity are considered to be just too desirable to forego.

Nevertheless, I suspect that without this type of labelling consistency being resolved across the language, these types of discussions will come up from time to time as an unavoidable consequence of the status quo.

With my best regards.

7 Likes

This seems a little uncharitable. The discussion has actually been really civil, and I see no reason for people interested in the topic to not participate here. Many examples and well-thought arguments were expressed very clearly, and the bits of conspiracy-theorizing seem to have been mostly dismissed by people interested in showing the intrinsic problems with the accepted design.

I disagree, it seems a waste of time to start another process for another proposal when this small improvement could be tackled right now, by the same people that work on the code side of the proposal, when the negative response is so overwhelming. Your tone and choice of words on Binding(get:set:) seems to dismiss the example as some kind of "fad", but it's actually representative of a class of problems that the proposal didn't solve, that is, constructors that take multiple closures.

I disagree: at least in my day-by-day, passing functions around is a core element of my craft, and over time more and more patterns and libraries are being based on this (including SwiftUI). I suggest you to check out these same patterns applied in languages without parameter labels: for example, APIs that take multiple closures in Kotlin are painful to use, and to read when reviewing code.

12 Likes

Hello Ben,

The only thing that is changing is the API guidelines. This should not be taken to imply that the guidelines will or even should be applied retrospectively, other than through further evolution proposals that would be considered individually.

Sure, but with the API guidelines changing in this direction, the one there seems to be the disagreement with, you can split those changes in separate evolution proposals, but I do not see each of them being amenable to more than bikeshedding and being likely and actually desirable to pass and get accepted.

I mean there would be no reasonable argument against changing the API’s: why would you want to have the standard library or UIKit or SwiftUI API’s not to be aligned to the API guidelines. The only argument would be a weak one: people not wanting such changes are people who disagree with a change to the guidelines that, after this proposal, will be considered “settled” and agreed upon.

2 Likes

I didn't think it was worth adding more comments on this mega thread but I keep thinking about it so just for my own sanity. So with all my respect please let me share my views on why I'm surprised this got that far.

I still think that this is not solving anything and is making a change on the language for no big win, when other pitches have stoped at the pitch phase just because of that reason.

But more concretely, from the motivation part of the proposal:

...and something about the asymmetry is unsettling.

but then the solution is not making anything symmetric, just moving the asymmetry to the first closure instead of the last one:

UIView.animate(withDuration: 0.3) {
  self.view.alpha = 0
} completion: { _ in
  self.view.removeFromSuperview()
}

To unsettle the asymmetry one would need to add both labels, not switch their order.

And another point that I find weird on a proposal that has been accepted is how it spends a big part of the Solution section explaining how for this proposal to be worth it APIs would have to change. Yes, maybe the proposal is not source breaking on itself but if APIs need to change to use it properly I don't see why that is not taken into account. (probably it was and decided not an issue, fair enough)

Digression: Personally, and I'm probably alone here, I still don't like any of the other alternatives that add labels after the closing parenthesis, the only thing you're doing with all of this is removing a parenthesis. The original trailing syntax is nice because you remove parenthesis AND labels (labels being what matters because in theory they are redundant), but with all the solutions proposed on these threads there is nothing that pulls it's own weight IMO.

17 Likes

filter(where:) is another one. According to my dictionary, a filter is "a porous device for removing impurities or solid particles from a liquid or gas passed through it" and to filter X from Y means to remove X from Y. In Swift, the inverse is true as the predicate specifies the elements to keep.

Also, filter, map, and reduce are confusing for novice programmers because their names imply that they’re mutating methods. I assume this falls under the "prior art" rule, but this doesn't apply to novices, who don't have any prior experience. Personally, I believe consistency is much more important here. There's just no way to convince a novice that sort is mutating but filter is not, and that this is fine for some reason...

Do you think there will ever be a chance to fix or patch this problem? No matter the syntax, I'm hoping we'll eventually have a solution where neither library authors nor users have to worry about multiple calling options, where the library author may have optimized for one, but the user is using the other.

7 Likes

Oh boy. This sort of comment really does nothing to elevate the discourse or to motivate the community.

The phrase “conspiracy theory” is especially galling. I mean, could you be any more dismissive? It does not come across well at all, and I feel that kind of language is beneath a member of the core team.

That’s aside from the fact that the very thing people are concerned about already happened (just a few months ago, no less). it’s a justifiable and rational concern, not a conspiracy theory.

Add to that the way this feature was rushed from pitch to review (with none of the pitch feedback being addressed, including criticism from members of the core team itself!), how the implementation was ready and actively worked on by several Apple employees across different parts of the toolchain, and now this acceptance which doesn’t appear to address most of the community feedback. Is it any wonder that people feel their voices are not being heard, and that some other voices are taking priority?

I would suggest that you reconsider whether or not these fears are as unreasonable as you claim, and how you characterise members of the community who express them.

This whole thread is a disaster, for the core team especially. The level of dismissiveness and borderline insulting language is eye-opening and will certainly have an impact on this community and language going forward.

38 Likes

This escalates even faster than I thought ;-)

I think now it's obvious that the expectations in the community aren't in sync with how the evolution process actually works — and that it would help to formally acknowledge that by changing the official documents accordingly.
The current situation sometimes feels like a charade to me, where people try to invent justifications to hide the fact that the process isn't driven by the community, but by the primary stakeholder.

I guess all of us know the realities of business, or had to sustain bad decisions from the management level themselves — that's something we are used to swallow, and it's better than cheating ourselves.
Heck, even if the whole core team actually believes that SE-0279 is the best possible solution, I think blaming WWDC would help us to accept what's going on...

2 Likes

While I understand this kind of concern, I'd like to point out that, personally, it doesn't really affect me. The idea that the core team decides what's best for the language, with some help form the community (and help was given), but no "constraint", is perfectly fine by me. Also, I'd say that broad statements and generalizations about the evolution process and its alleged tricking of the community into thinking that the latter "counts" is not useful: I think that's not the case at all, and it could alienate and indispose the core team.

My problem here is that I find the rational arguments to justify the design and its acceptance to be weak, and even weaker are the arguments against the optional first label. If the authors provided some kind of draft of a possible future solution that would have clashed with an optional first label, I would have accepted it gladly.

If, for example, the proposal (or even the acceptance) contained something like: "a possibility would be to introduce a @notrailing annotation to prevent users and autocompletion to use the trailing closure syntax in cases where there's no clear main closure", it would have justified focus on just APIs where the "main" closure is present. I would have accepted it, even if it was a future direction. But without even a hint at something like this, the accepted design feels incomplete, because it takes off to solve the multiple trailing closures problem in Swift, but only solves part of it, while a very little more work could have solved both, albeit with an imperfect solution given the historical flaw related to trailing closures in general.

5 Likes

The reads like you're proving the point. There's another explanation to perceived slight, that the community's negative feedback hasn't been respected because it doesn't seem credible. I'm sorry for sounding dismissive (:canada:).

The new syntax is additive. It add an option to improve some function calls that were awkward previously. Normal call syntax can be used wherever the coder thinks the new syntax is not an improvement.

Complaint seems to be (I think this was the only response when I asked): there's a new way to write code that looks bad and omits labels an API author never intended. However trailing closure syntax could always be used to write code that looks bad and omits labels an API author never intended:

UIView.animate(withDuration: 0.3, animations: {
  self.view.alpha = 0
}) { _ in
  self.view.removeFromSuperview()
}

There's been silent acceptance of this problem since 1.0 (IIRC), the solution has always been: don't use a language feature where it doesn't make sense. The same applies after SE-0279.

Community members who think this could be improved even more to make more cases of multiple trailing closures work well, it's been made clear what the core team thinks the new baseline should be. There are clear openings for additive improvement.

Those seeing something rotten in the process, perhaps find a better case to argue on, to me this one seems like a strawman.

3 Likes

I certainly wouldn't count as a "well informed" person myself. In fact, I've posted some really uninformed posts in the recent history. Saying that, I'm not here to fight the Core Team nor Apple. I'm here because I do care about Swift and I assume everyone here does. Therefore I don't think it's reasonable to talk about "conspiracy theories" when it comes to people mentioning the WWDC. I wish this discussion would cool down. At the same time, I want to mention, that I find Core Team's reaction to the WWDC mentions a little bit unwarranted. Last year we got proposals like Function Builders. Personally I wish the Core Team would provide further reasoning for not allowing the first label to appear so we can move beyond this and possibly create the amending proposal as suggested by the Core Team.

12 Likes

Exactly. I don’t think it’s unreasonable to infer from this that there is timeline pressure to land what has been implemented. We all face such pressures in our work and would not fault anyone for leaving enhancements, even very highly requested ones, for the future.

It is certainly unusual for a rationale to leave a very predominant theme of the review feedback completely unaddressed. Even after more than 150 messages in this thread nobody from the core team has clearly and directly addressed that feedback.

The community is speculating about the rationale for not incorporating this feedback into a revised proposal because no explanation has been given. The only thing the community can do if they wish to understand the decision is to make inferences based on available information, including the context in which the decision has been made.

This is an unfortunate situation and I think it would be beneficial to everyone in the community (including the core team) if a more clear and direct reason for accepting the proposal without incorporating our feedback was provided. Perhaps with such an explanation in hand and guidance for the future the community would be able to move on in a more productive direction and we can all learn from this experience.

Exactly. Accepting a proposal in a state that appears to many to be a partial solution with no acknowledgement of that fact or statement of intent for a broader direction is what has caused such strong reaction.

31 Likes

Like most others, I personally have no problems with SE not being a democracy and having the Core team steer the language development. I think that you guys have been doing amazing job so far. I write Swift code every day and I enjoy it. It makes my work interesting. Thank you for that.

For that kind of leadership to work, though, it is important that the community trusts you to make rational and founded decisions. You have proven yourselves capable of doing that countless number of times, however this proposal seems to be an exception. The awkward silence from your side makes it only worse.

There have been so many questions about optionally allowing the first trailing closure label. It seems like a relatively small addition to the proposal that would alleviate the pressure of making hard decisions at this moment. It would be great to hear your feedback on that.

39 Likes