Side note: when converting a project to Swift 4, I’ve encountered quite a few 
Quality of Life regressions that could also be related:

Regression 1

When using this library https://github.com/socketio/socket.io-client-swift:

public typealias NormalCallback = ([Any], SocketAckEmitter) -> Void

class Socket {
    func on(_ event: String, callback: @escaping NormalCallback) -> UUID { … }
}

My code had to be modified from:

socket.on(“message”) { _ in
    print(“got message")
}

to:

socket.on(“message”) { (_, _) in
    print(“got message")
}

Regression 2

When using RxSwift: https://github.com/ReactiveX/RxSwift 
<https://github.com/ReactiveX/RxSwift> (simplified example):

public class Driver<E> {
    func drive(onNext: ((E) -> Void)) -> Disposable {}
}

I had to change the following code:

let driver: Driver<Void> = …
driver.drive(onNext: {
    print(“onNext")
})

to:

let driver: Driver<Void> = …
driver.drive(onNext { _ in
    print(“onNext")
})

Regression 3

Also with RxSwift (simplified example):

public class Driver<E> {
    func onNext(_ element: E) { … }
}

I had to change the following code:

let driver: Driver<Void> = …
driver.onNext()

to:

let driver: Driver<Void> = …
driver.onNext(())

Conclusion

Basically, these regressions add synctactic pollution to quite a few cases 
turning around tuples and Void.

David.

> On 8 Jun 2017, at 12:08, David Hart via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>> 
>> On 8 Jun 2017, at 11:17, Gwendal Roué via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>>> Le 8 juin 2017 à 19:40, Brent Royal-Gordon via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>>> 
>>>> On Jun 7, 2017, at 3:03 AM, Adrian Zubarev via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> Well please no:
>>>> 
>>>> 
>>>>  let fn2: ((Int, Int)) -> Void = { lhs, rhs in } 
>>>> 
>>>> Instead use destructuring sugar pitched by Chris Lattner on the other 
>>>> thread:
>>>> 
>>>> let fn2: ((Int, Int)) -> Void = { ((lhs, rhs)) in }
>>>> 
>>> 
>>> I think this suggestion is better than the status quo. I'm wondering, 
>>> though, if we should just drop the outer set of parentheses entirely, 
>>> unless you're also putting types on the parameters. That is, a closure of 
>>> type `(Int, Int) -> T` can look like this:
>>> 
>>>     { (x: Int, y: Int) in … }
>>> 
>>> Or it can look like this:
>>> 
>>>     { x, y in … }
>>> 
>>> But it *cannot* look like this:
>>> 
>>>     { (x, y) in … }
>>> 
>>> The `(x, y)` form can instead be a closure of a type like `((Int, Int)) -> 
>>> T`, which immediately destructures the tuple parameter into separate 
>>> constants.
>>> 
>>> -- 
>>> Brent Royal-Gordon
>>> Architechies
>> 
>> Hello,
>> 
>> There's a difference, in the mind of people here that try to show how bad 
>> were the recent changes, between:
>> 
>> 1: closures defined independently
>> 2: closures given as a parameter to a function.
>> 
>> I think that we all agree that the type of a closure that is defined 
>> independently should be well defined:
>> 
>>     // Choose between (Int, Int) -> () or ((x: Int, y: Int)) -> ()
>>     let a = { (x: Int, y: Int) -> Int in ... }
>>     let b = { ((x: Int, y: Int)) -> Int in ... }
>> 
>> However, when a closure is given as an argument of a function that expects a 
>> closure, we ask for the maximum possible flexibility, as Swift 3 did:
>> 
>>     func wantsTwoArguments(_ closure: (Int, Int) -> Int) { closure(1, 2) }
>>     wantsTwoArguments { a, b in a + b }
>>     wantsTwoArguments { (a, b) in a + b }
>>     wantsTwoArguments { t in t.0 + t.1 } // OK, maybe not
>> 
>>     func wantsATupleArgument(_ closure: ((Int, Int)) -> Int) { closure((1, 
>> 2)) }
>>     wantsATupleArgument { a, b in a + b }
>>     wantsATupleArgument { (a, b) in a + b }
>>     wantsATupleArgument { t in t.0 + t.1 }
>>     
>>     func wantsANamedTupleArgument(_ closure: ((lhs: Int, rhs: Int)) -> Int) 
>> { closure((lhs: 1, rhs: 2)) }
>>     wantsANamedTupleArgument { a, b in a + b }
>>     wantsANamedTupleArgument { (a, b) in a + b }
>>     wantsANamedTupleArgument { t in t.lhs + t.rhs }
>> 
>> This gives us the ability to deal with unfitted function signatures. For 
>> example, most Dictionary methods. Yes, they are usually unfitted:
>> 
>>     extension Dictionary {
>>         func forEach(_ body: ((key: Key, value: Value)) throws -> Void) 
>> rethrows
>>     }
>> 
>> Who cares about this named (key:value:) tuple? Absolutely nobody, as 
>> exemplified by this remarquable Swift 3 snippet below, where no tuple, no 
>> `key`, and no `value` is in sight:
>> 
>>     let scores: [String: Int] = ... // [playerName: score]
>>     scores.forEach { name, score in
>>         print("\(name): \(score)")
>>     }
>> 
>> Do you see?
> 
> This post is the one that makes most sense to me! Be strict on definition but 
> flexible on use.
> 
>> Gwendal
>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to