> Le 9 juin 2017 à 07:56, Vladimir.S via swift-evolution 
> <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"
    overloaded { _ in 1 }               // error: ambiguous use of 'overloaded'
    overloaded { (_) in 1 }             // "overloaded 1"
    overloaded { (_, _) in 1 }          // "overloaded 2"

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

Reply via email to