> On Jun 8, 2017, at 11:37 PM, Gwendal Roué via swift-evolution > <swift-evolution@swift.org> wrote: > > >> Le 9 juin 2017 à 07:56, Vladimir.S via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit : >> >> Yes, we are discussing the *potential* solutions for Swift 4 that can >> decrease the pain of migration of *some* Swift3 code, given (Int,Int)->() >> and ((Int,Int))->() are different types in Swift 4. >> >> But, as was said by Mark Lacey in this thread later, there is an "overload" >> problem for such solution, when closure of kind {x, y in ..} can be sent to >> overloaded func like here: >> >> func overloaded(_ fn: (Int, Int) -> Int) { fn(1,2) } >> func overloaded(_ fn: ((Int, Int)) -> Int) { fn((3,4)) } >> >> overloaded { x, y in x + y } >> overloaded { (x, y) in x + y } >> >> Compiler is not able to determinate which type of closure do you want in >> each case. For ((Int,Int))->Int you still need some 'specific' syntax which >> disambiguate the call. So we *still* need some good syntax to destructure >> tuple argument in closure to use in place of ((Int,Int))->Int closure. >> >> This means that there is no sense to allow very 'magic' {x,y in ..} syntax >> and compiler-detected&generated type of closure if we still need good syntax >> for destructuring tuple argument in ((Int,Int))->(). > > Yes, Mark was very right asking about overloads. But is it a problem that > does not have a solution which preserves ergonomics? > > func notOverloaded1(_ closure: (Int, Int) -> Int) -> String { return > "notOverloaded1" } > func notOverloaded2(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { > return "notOverloaded3" } > > func overloaded(_ closure: (Int, Int) -> Int) -> String { return > "overloaded 1" } > func overloaded(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { > return "overloaded 2" } > > // not overloaded => not ambiguous > notOverloaded1 { x, y in x + y } > notOverloaded1 { (x, y) in x + y } > notOverloaded1 { _ in 1 } > notOverloaded2 { x, y in x + y } > notOverloaded2 { (x, y) in x + y } > notOverloaded2 { _ in 1 } > > // overloaded => resolve ambiguity on closure argument, when possible > overloaded { x, y in x + y } // "overloaded 1" > overloaded { (x, y) in x + y } // "overloaded 1" > overloaded { t in t.lhs + t.rhs } // "overloaded 2" > overloaded { (t) in t.lhs + t.rhs } // "overloaded 2”
This is exactly what happens today as a result of SE-0110 since the first two calls take two arguments, and the next two take a single argument. > overloaded { _ in 1 } // error: ambiguous use of > ‘overloaded' With SE-0110 in its current form, this calls the tuple version since there is a single closure parameter listed. > overloaded { (_) in 1 } // "overloaded 1” With SE-0110 in its current form, this calls the tuple version since there is a single closure parameter listed. I don’t understand why you would suggest this should call the two-argument version since that’s inconsistent with the other closures above that have a single argument. > overloaded { (_, _) in 1 } // "overloaded 2” With SE-0110 in its current form, this calls the two-argument version since there are two listed arguments. Mark > See the error on `overloaded { _ in 1 }`, because _ means "I don't care". > Well, here you have to care because of overloading. Ambiguity is resolved > with parenthesis. This is a specific behavior for `_`. > > Gwendal > > ------- > > PS, I had a little look at how Swift 3 currently behave with overloading ? > Badly, actually: > > // SWIFT 3 > > func f(_ closure: (Int, Int) -> Int) -> String { return "two arguments" } > // error: invalid redeclaration of 'f' > // func f(_ closure: ((Int, Int)) -> Int) -> String { return "one > anonymous tuple argument" } > func f(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { return "one > named tuple argument" } > > // error: ambiguous use of 'f' > // f { x, y in x + y } > > f { t in t.rhs + t.lhs } // "one named tuple argument" > > // error: ambiguous use of 'f' > // f { t in t.0 + t.1 } // "one named tuple argument" > > // error: ambiguous use of 'f' > let c = { (a: Int, b: Int) -> Int in a + b } > type(of: c) // ((Int, Int) -> Int).Type > // error: ambiguous use of 'f' > // f(c) > > Swift 3 does not allow overloading ((Int, Int)) -> Int and (Int, Int) -> Int, > but allows overloading ((lhs: Int, rhs: Int)) -> Int and (Int, Int) -> Int. > > Yet I could never call the (Int, Int) -> Int version, even when I provide > with a function that exactly matches its signature. And there are much too > many ambiguous situations the compiler can't deal with. > > So yes, there is a problem with Swift 3. > > How is it with Swift 4 (2017-06-02 snapshot)? > > // SWIFT 4 > > func f(_ closure: (Int, Int) -> Int) -> String { return "two arguments" } > // error: invalid redeclaration of 'f' > // func f(_ closure: ((Int, Int)) -> Int) -> String { return "one > anonymous tuple argument" } > func f(_ closure: ((lhs: Int, rhs: Int)) -> Int) -> String { return "one > named tuple argument" } > > f { x, y in x + y } // "two arguments" > f { t in t.rhs + t.lhs } // "one named tuple argument" > f { t in t.0 + t.1 } // "one named tuple argument" > > let c = { (a: Int, b: Int) -> Int in a + b } > type(of: c) // ((Int, Int) -> Int).Type > f(c) // "two arguments" > > Much better. > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution