I have to admit I’m quite fond of the trailing closure syntax. This is partly 
because of my earlier experiences with Ruby. But partly I just really found it 
more readable to see a separation between a regular function call, with just 
normal parameters passed in, and higher order functions, like the `map` example 
you’ve made. Having two sets of parentheses/braces like foo({ … }) really makes 
them blend in and I don’t notice the curly braces as much. Having a stylistic 
separation between:

        foo(argument)
        foo { code }

helps me catch the difference between the two.

But it is a stylistic choice. Like I mentioned in a different reply, if we’re 
going to have trailing closures at all, I don’t see a point in enforcing this 
other than with a linter.

* * *

The only way I see this working is if the trailing closure syntax has *other* 
semantics as well. For example, there’s been a discussion about allowing 
specially marked closures to return/break/continue in the scope of the caller 
function, not the closure’s scope (like Ruby’s blocks do). Now, that would make 
a bit more sense. You’d have a special attribute (can’t think of a name, but 
let’s stick with your @trailing), that would imply:

- required trailing closure syntax
- @noescape, I think
- and return/break/continue affects outside functions

And you could use that to make your own pseudo-language-constructs. This would 
enforce trailing closure syntax, and nothing else could use trailing closure 
syntax.

Now, I wouldn’t be super happy about not being able to write `map { foo }` 
myself 😁 — but _that_ proposal would make sense to me. It wouldn’t just be 
enforcement of a stylistic choice, but the syntax would actually convey some 
important semantics.

What do you think?

— Radek

> On 24 Mar 2016, at 14:57, Haravikk via swift-evolution 
> <[email protected]> wrote:
> 
> When I started using Swift I was initially very enthusiastic about trailing 
> closures, but I’ve actually kind of gone off them somewhat and I’d like to 
> discuss why.
> 
> Firstly, here are two ways to write a common example using the .map() method:
> 
>       let foo = myArray.map { $0 + 1 }
>       let foo = myArray.map({ $0 + 1 })
> 
> It’s tough to say that the first form is any neater than the second, other 
> than the second having more brackets. However, the first form is somewhat 
> ambiguous, as .map in this case looks like a property rather than a method, 
> it also visually looks like a statement, followed by a closure rather than 
> the two things logically being related. Of course it’s quick to learn that 
> these are related, but for consistency I’m starting to now prefer the use of 
> parenthesis in almost all cases.
> 
> The other advantage of trailing closures is the omission of the label, but 
> trailing closures aren’t strictly necessary for this, as we can already omit 
> external labels for parameters if we want to, and the example above shows 
> that a trailing closure isn’t necessary for this. The only real difference is 
> that the trailing closure form makes a label optional, because you can either 
> provide the closure with label in parenthesis (if the label is required) or 
> omit it by trailing, like so:
> 
>       something.someMethod(foo: 1, predicate: { $0 < $1})
>       something.someMethod(foo: 1) { $0 < $1}
> 
> However this kind of arbitrarily makes the following impossible:
> 
>       something.someMethod(foo: 1, { $0 < $1 })
> 
> With this in mind it seems to me that we might be better served by the 
> ability to make external labels optional, as this would allow us to be just 
> as succinct, while being completely clear about what is being passed into 
> this method.
> 
> 
> The only real remaining advantage that I see to trailing closures is the 
> ability to define pseudo language constructs, for example:
> 
>       func repeatUntilEmpty<C:CollectionType>(collection:C, @noescape _ 
> body:() throws -> Void) rethrows { while !collection.isEmpty { body() } }
>       repeatUntilEmpty(myArray) {
>               /* Do something over and over until myArray is empty */
>       }
> 
> Which I think is a pretty uncommon type of structure, but could be useful in 
> some specialised situations. To support this though we could easily use a new 
> @trailing attribute instead to indicate that the closure can be used in this 
> way. My example isn’t very good as I can’t think of a case that really, 
> really needs this, but I think they’re probably out there.
> 
> 
> To summarise, having come down off my initial enthusiasm for trailing 
> closures I’m not sure that they really add that much syntactically, 
> especially in the most common cases, while actually being a little ambiguous 
> looking and adding inconsistency to the language. I think they should remain 
> for the less common cases that can really benefit from them, but as a feature 
> that is opted into, so that we can go for consistency by default.
> 
> I’m interested to hear other people’s thoughts.
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to