[Accepted] SE-0279: Multiple Trailing Closures

I don't think this is the case. Even a in 300+ posts thread, a single argument, well constructed, logically solid and unchallenged by equally robust counterarguments, should be considered strong enough to shift a proposal in a certain direction. For purely syntactic sugar proposals like this one it's usually harder to construct arguments in favor of (or against) something without eventually using one's "personal preference" as key hypothesis.

But in this discussion it has been shown, with countless examples, arguments, framings, whatever, that there are cases, even right now, in the libraries that we use every day, where this proposal falls short hard, and these things were simply not taken into account by the accepted design: I'm fine with doing the minimum amount of useful work, in order to achieve a gradual evolution, but the proposal doesn't reach this minimum.

I didn't get this impression, I simply find some aspects of the rationale to be irrational. The only possible explanation I can think of is that making the label for the first closure optional would be a gigantic thing to develop: I'm not an expert, and if this is the reason why we're going with this demonstrably sub-par design, I really would like to know, and would have liked that it was put in the rationale. If it's not, if it's a simple addition, then the design is simply irrational.

I very strongly disagree with all three:

  1. it solves a very specific case of a class of problems - many of us have been annoyed with also other cases - and there's no reason to just focus on one while neglecting the others;
  2. true, but allowing for an optional label on the first closure, that would eventually been required, first with a warning, and then progressively with an error, would have been source compatible (for example, tuple binding in switch cases emits a warning right now); I understand the fact that, given that a complete redesign might be needed for trailing closures in general, it's not a good idea to require some specific syntax right now, but an optional first parameter label wouldn't have hurt, with an autocompletion behavior based on whether the latter has actually a value or it's _:;
  3. I don't think it is; it's smaller than the smallest, Albert Einsten would have said that it's simpler than "as simple as possible". Parameter labels are swifty; dropping a label in a list of labeled parameters for no reason is not. Even the rationale clearly states that if we could redesign the trailing closure syntax, we would.

There's a simple case for a label to be dropped, and it's the same for other parameters: when it's _:. That is swifty.

If an acceptance rationale has so many negative responses, such a negative feedback, there must be something wrong. The mental experiment would be to put all these in the amended review thread, and think if the outcome would have been the same. I suspect it would have been, due to the lack of responses from the authors (apart from the always patient John) in this thread. It's seems clear that the authors simply thought that, in case of "symmetric" APIs, one would expect that the non-trailing syntax is used, but this could have been so much better.

The proposal has a very, very poor justification for not allowing an optional label on the first parameter:

Recall: API authors should be naming functions assuming that the argument label of the first trailing closure will be dropped is literally something that the proposal just added: this is a circular argument.

Swift users aren’t used to seeing function names and argument labels juxtaposed without parenthesis, true, as they're not used to see the new syntax, but that doesn't mean we're not adding it. "Not used to" is not a good argument against new syntax, which is of course something people are not used to.

Many find this spelling unsettling., and a huge lot more find the design terrible for "symmetric" APIs.

Anyway, we'll somehow find some way to work with this, but it could have been hugely better with (seemingly) little effort.

18 Likes

This anti-pattern (of having a "throw away" first closure) is looking more appealing each day.

A handful of people in the review thread suggested this syntax:

function()
    first: { ... }
    second: { ... }

as an alternative to this:

function
    first: { ... }
    second: { ... }

While the anti-pattern may not be as pretty, it gets us pretty close.

The sad thing is that if it does become what's seen as a "workaround" to achieve what the vast majority of us wanted in the first place (optional first argument labels) then it will become such at the cost of adding "throw away" code.

And honestly, I think it may be worth the cost.

I'd rather write:

Binding {}
    get: { ... }
    set: { ... }

than:

Binding
    { ... }
    set: { ... }

For all sad words of tongue and pen, The saddest are these, 'It might have been'.

10 Likes

I certainly hope nobody writes code like this.

While I would prefer to write:

Binding
   get: { ... }
   set: { ... }

I would continue writing:

Binding(
   get: { ... },
   set: { ... }
)

over either of the forms you suggested (and feel disappointed in Swift every time I do).

15 Likes

I think you missed my point. Though, I should've clarified:

Ranking my preferences for that case:

  1. Not using trailing closures: Binding(get: { ... }, set: { ... })
  2. The "workaround"
  3. Multiple trailing closures

The point is that this new feature which is supposed to improve the language, will (for symmetric APIs), in my opinion, rank lower in preference than a workaround.

That should be telling us something. (What a lot of us already know...)

10 Likes

Thank you for the clarification. I think we are mostly in agreement. I dislike both 2 and 3 enough that it's hard for me to give a relative ranking. I agree that the call site for 2 looks better, but the hack is pretty hard to swallow.

3 Likes

Hi – this feels like a breakout thread. I don’t plan on closing this thread for further comments, but we need to avoid it being a design scratchpad for other ideas.

It isn't.

I'm pointing out that the decision has a chance of pushing the use of this feature in a direction that the core team might not have intended.

13 Likes

I disagree, and I’ll be forced to close this thread to all comments if it continues in this direction. Please take design discussions to a new thread elsewhere.

@Ben_Cohen In response to @clayellis's post you say the thread is being used as a “design scratchpad for other ideas” and warn us to stop. @clayellis says we're not doing that. I happen to agree—at the very least, he's not doing that; he's talking about of the impact the change will have on coding patterns. If you're going to disagree and threaten to shut the thread down, it seems to me the least you can do is point specifically to what language you think constitutes this use as a design scratchpad.

29 Likes

Please don't do that. This would only exacerbate the already negative mood caused by the steering committee's decision.

Kind regards,

Lars

9 Likes

I wouldn't feel too badly. Like method call syntax when compared to function call syntax, the most significant benefit of trailing closure syntax was always that it removed a level of nested structure in the syntax. Nesting is, generally speaking, harder to understand.

As soon as we put closures on their own indented lines, though, those advantages are gone: we are still representing nesting structure syntactically (and if you think indentation doesn't amount to syntactic nesting structure, I refer you to Python). As you can see from your example, clarity at the use site is not harmed by the parentheses and the comma, so AFAICT there wasn't much to be gained.

8 Likes

[EDIT: the below isn't helpful, sorry about that. I'm leaving it here for posterity]

Dramatic sigh. There is a lot of nonproductive discourse and conspiracy-theorizing in this thread that's drowning out any well-reasoned feedback and specific suggestions. It's chased away people who have well-informed opinions on this topic.

If the goal is to effect change, the productive way to do that is to create a separate thread to discuss a specific proposal for a change. I think the thing people are most asking for is to allow an (optional) argument label on the first trailing closure (Binding(get:set:) is trendy now). That is a pure extension on top of the accepted proposal that can be motivated on its own.

Doug

12 Likes

I restate my concern.

Having a separate proposal does nothing to address the "trial period" and the damage that it could cause.

8 Likes

I won't :wink:, but it will always seem like an opportunity for improvement in the language.

The gain is admittedly small, but every little bit of syntax adds up. I like definitely prefer the cleaner syntax.

More important IMO is the fact that consistency in syntax for closures (always being in trailing form) would be very nice to have. If a label were allowed on the first trailing closure we could adopt trailing closures as the universally idiomatic style in Swift. It think this consistency would be a larger win.

1 Like

That doesn't seem particularly productive.

Like I asked @Ben_Cohen, I ask you to be specific about what you consider “nonproductive discourse and conspiracy-theorizing.” Your post and Ben's both seem to be trying to moderate something, but it's unclear what. The most obvious trigger—the post Ben responded to—was neither “design” nor “conspiracy theorizing.” The only conclusion I have left is that either:

  • you think it's “nonproductive” to discuss how code will be written when this feature lands, or
  • you are trying to moderate posts other than the one Ben responded to, or
  • you've misunderstood the post Ben responded to.

Some people have asked for that, but that discussion doesn't seem to be what's sparked this moderation activity. I'm certainly engaged in this part of the discussion because I think it's a good thing to understand better. I have no hope effecting the change I'd like. If you want to redirect the discussion, please be specific about what you're after.

11 Likes

Assuming your question wasn't rhetorical, you can search for "WWDC" yourself to see what I'm talking about. Threads in which posters are questioning the motivation of others---whether they are proposers, members of the Core Team, or anyone else---dissuade people from engaging in technical discussions.

As I said before, if your goal is to effect change, you will have more impact by doing it in another thread and not being associated with the toxicity I mention above.

There are two concerns here that are getting entangled---toxicity and the desire not to design new things in an announcement thread. Both of those push toward the same answer, which is to start a new thread to propose an alternative. I have made that suggestion in the clearest way I know how.

Doug

6 Likes

Of course it wasn't rhetorical. I've seen those posts. The problem is that your reply to my reply to Ben's reply to @clayellis carries with it a strong implication that you're talking about something else, effectively chastising particular posters who weren't engaged in that…

There are two concerns here that are getting entangled---toxicity and the desire not to design new things in an announcement thread.

…and it didn't help clarity at all that your reply to me really had nothing to do with Ben's complaint or what I was challenging.

As I've been trying to say, there's no realistic alternative I can propose. I'm just trying to understand the implications of the decision, both for existing code and for future evolution proposals. If you want to declare this thread poisoned because of earlier conspiracy-theorizing, and suggest that all productive discussion move elsewhere, I can dig that.

3 Likes

Likewise.

1 Like

For what’s its worth, I think the final decision the Core Team made was pretty sensible: it feels like a natural extension to the current behavior of trailing closures. And even if we don’t all agree, this is a fairly small change in a small part of the language that only shows up in the rare APIs with multiple closures, which is not very frequent. I hope we can all continue discussing this with a bit less emotion.

8 Likes

I don't know if that would be very comforting. If we all agreed that this was a "small change...small part of the language...rare APIs...not very frequent," then it should never have passed the high bar for adding syntactic sugar to the language. (This, by the way, was the argument advanced by several people who are displeased with the result.)

Moreover, putting aside the aspersions cast, I think the length and tenor of these conversations truly does reflect (despite attempts to characterize otherwise) a dissatisfaction not limited to the subject matter but rather the process. Many in the community were of the impression (and have expressed it here) that a strong consensus for a modification to the proposal was achieved during review, and further that this consensus was not reflected in the result, nor even mentioned more than obliquely.

I think we are here in a process of reflection among community members, though certainly not all directions have been--shall we say--productive. It would be encouraging if the core team were to engage to foster a more healthy introspective moment but it appears the preferred solution is to cut the process short.

27 Likes