[swift-evolution] [Proposal] Disallow implicit conversion between function/closure with a list of parameters and with tuple parameter. Remove function type inconsistency.
Vladimir.S
svabox at gmail.com
Sat Jun 25 10:35:54 CDT 2016
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.
More information about the swift-evolution
mailing list