[swift-evolution] [Proposal] Disallow implicit conversion between function/closure with a list of parameters and with tuple parameter. Remove function type inconsistency.

Haravikk swift-evolution at haravikk.me
Mon Jun 27 05:10:58 CDT 2016


+1 to this; I seem to keep running into cases of this, and it crops up especially when Swift is having difficulty inferring a type, which can be tricky to debug as it is, so I think it's better to just be consistent and explicit, with double brackets for all tuple type closures as proposed.

> On 25 Jun 2016, at 16:35, Vladimir.S via swift-evolution <swift-evolution at swift.org> wrote:
> 
> I believe this should be done for Swift 3.0 release as this is a *source breaking change* and IMO it is very important to remove the inconsistency mentioned below.
> 
> We removed tuple splatting on caller side and IMO we must complete this job to delete the implicit connection between tuple and list of parameters in closures/functions.
> 
> 
> Currently we have these "features" :
> ====================================
> 
> 1. Single tuple as parameter is allowed when list of parameters are required:
> 
> let ft1 : (Int,Int) -> Void = { x in print(x.0, x.1)}
> 
> (but this causes crash:
> let ft2 : (Int,Int) -> Void = { x in print(x) }
> )
> 
> Opinion: this should not be allowed. Parameter list is required.
> `(Int,Int) -> Void` and `((Int,Int)) -> Void` are two different types.
> 
> 
> 2. Parameter list in closure is allowed when single tuple parameter is required:
> 
> typealias IntInt = (Int,Int)
> typealias IntIntToVoid = (IntInt) -> Void
> 
> let tuple : IntInt = (1,2)
> 
> func foo(block: IntIntToVoid) { block(tuple) }
> 
> foo { x, y in print(x,y)}
> foo { (x, y) in print(x, y)}
> 
> Opinion: this should not be allowed. Tuple parameter is required.
> `((Int,Int)) -> Void` and `(Int,Int) -> Void` are two different types.
> Swift should require this syntax to assign tuple parameter's sub-values to variables in closure: `{ ((x, y)) in ..}`
> 
> 
> 3. Inconsistent (and just wrong) function type when a list of parameters required(not tuple) :
> 
> typealias t1 = (Int, Int) -> Int // clearly here are list of parameters
> typealias t2 = ((Int, Int)) -> Int // clearly here is a tuple parameter
> 
> print(t1.self) // Prints ((Int, Int)) -> Int  why?
> print(t2.self) // Prints ((Int, Int)) -> Int
> print(t1.self == t2.self) // true
> 
> Opinion: `(Int,Int) -> Void` and `((Int,Int)) -> Void` should be two different separate types that can not be implicitly converted to each other. Swift's typesystem should separate these types.
> 
> 
> 4. If the type is the same, why behavior differs :
> 
> let add_list:  (Int, Int) -> Int = (+)
> let add_tuple: ((Int, Int)) -> Int = (+)
> 
> print(add_list.dynamicType == add_tuple.dynamicType) // true
> 
> print( add_list(1,2) )
> //print( add_list((1,2)) ) // missing argument for parameter #2 in call
> 
> //print( add_tuple(1,2) ) // extra argument in call
> print( add_tuple((1,2)) )
> 
> 
> Proposal:
> ===============
> 
> 1. Separate function types with parameter list and a tuple parameter. They should be two separate types.
> 
> 2. Require this syntax to assign tuple parameter's sub-values to variables in func/closure: `{ ((x, y)) in ..}`, otherwise (i.e. if `{ (x, y) in ..`) treat function/closure as having list of parameters.
> 
> 3. Disallow implicit conversion between function/closure with a list of parameters and function/closure where single tuple is required.
> This will stop confusion and make the language consistent how it deal with tuples and list of parameters in func/closure.
> 
> 4. It seems like we should keep the ability to explicitly convert one to another as some(many?) code can depend on this current behavior and so we need a way to convert old code to new.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list