57 lines (36 sloc) 2.54 KB

Distinguish between single-tuple and multiple-argument function types


Swift's type system should properly distinguish between functions that take one tuple argument, and functions that take multiple arguments.

Discussion: pre-proposal


Right now, the following is possible:

let fn1 : (Int, Int) -> Void = { x in
	// The type of x is the tuple (Int, Int).
	// ...

let fn2 : (Int, Int) -> Void = { x, y in
	// The type of x is Int, the type of y is Int.
	// ...

A variable of function type where there exist n parameters (where n > 1) can be assigned a value (whether it be a named function, a closure literal, or other acceptable value) which either takes in n parameters, or one tuple containing n elements. This seems to be an artifact of the tuple splat behavior removed in SE-0029.

The current behavior violates the principle of least surprise and weakens type safety, and should be changed.

Proposed solution

We propose that this behavior should be fixed in the following ways:

  • A function type declared with n parameters (n > 1) can only be satisfied by a function value which takes in n parameters. In the above example, only the fn2 expression would be considered valid.

  • To declare a function type with one tuple parameter containing n elements (where n > 1), the function type's argument list must be enclosed by double parentheses:

     let a : ((Int, Int, Int)) -> Int = { x in return x.0 + x.1 + x.2 }

    We understand that this may be a departure from the current convention that a set of parentheses enclosing a single object are considered semantically meaningless, but it is the most natural way to differentiate between the two situations described above and would be a clearly-delineated one-time-only exception.

Impact on existing code

Minor changes to user code may be required if this proposal is accepted.

Alternatives considered

Don't make this change.