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