[Discussion] func/closure parameters and tuples


(Vladimir) #1

I wanted to ask if the below behavior of compiler/parser is bug or it is 'feature' and 'by design' and we will not change this :

1. I was not expecting this will compile :

let ft1 : (Int,Int) -> Void = { x in print(x.0, x.1)}

ft1(1, 2)

the type of ft1 is definitely not the same as closure

2. The same. But this crashes compiler at compile time(if I understand correctly) :

let ft2 : (Int,Int) -> Void = { x in print(x) }

ft2(1, 2)

···

----------
Unhandled conversion from exploded tuple
...
1. While emitting reabstraction thunk in SIL function @_TTRXFo_iP___XFo_dSidSi__<unknown>:0: error: unable to execute command: Aborted
<unknown>:0: error: compile command failed due to signal (use -v to see invocation)
----------

3. Was expecting closure will require a single argument, which is tuple; but it accepts even just x, y

typealias IntInt = (Int,Int)

func foo(block: (IntInt) -> Void) {
     let z : IntInt = (1,2)
     block(z)
}

foo { x in print(x)} // ok
foo { x, y in print(x,y)}
foo { (x, y) in print(x, y)}

I'm not sending two values to closure, I send one instance which is tuple.

Shouldn't we add consistency in Swift regarding allowed argumets of closure if tuple is required as parameter?


(Vladimir) #2

Even more 'stranges' :

typealias BinaryIntOp_v1 = (Int, Int) -> Int
typealias BinaryIntOp_v2 = ((Int, Int)) -> Int

print(BinaryIntOp_v2.self) // Prints ((Int, Int)) -> Int why?
print(BinaryIntOp_v2.self) // Prints ((Int, Int)) -> Int

let areRepresentingTheSameType = BinaryIntOp_v1.self == BinaryIntOp_v2.self // (alt-click the "==" and read doc.)
print(areRepresentingTheSameType) // Prints true

let add_v1: BinaryIntOp_v1 = (+)
let add_v2: BinaryIntOp_v2 = (+) // Or both could have been eg: { return $0 + $1 }

let ra = add_v1(1, 2)
let rb = add_v2((1, 2)) // NOTE: Needs these extra parens (otherwise error: "Extra argument in call")

let rc = (add_v1 as BinaryIntOp_v2)((1, 2)) // NOTE: I am type casting these to an identical type ...
let rd = (add_v2 as BinaryIntOp_v1)(1, 2) // ... in order to swap which one of them need extra parens ...

I believe we should fix this inconsistency before Swift 3.0 is released as this could be source-breaking changes. Opinions?

···

On 21.06.2016 21:28, Vladimir.S wrote:

I wanted to ask if the below behavior of compiler/parser is bug or it is
'feature' and 'by design' and we will not change this :

1. I was not expecting this will compile :

let ft1 : (Int,Int) -> Void = { x in print(x.0, x.1)}

ft1(1, 2)

the type of ft1 is definitely not the same as closure

2. The same. But this crashes compiler at compile time(if I understand
correctly) :

let ft2 : (Int,Int) -> Void = { x in print(x) }

ft2(1, 2)

----------
Unhandled conversion from exploded tuple
...
1. While emitting reabstraction thunk in SIL function
@_TTRXFo_iP___XFo_dSidSi__<unknown>:0: error: unable to execute command:
Aborted
<unknown>:0: error: compile command failed due to signal (use -v to see
invocation)
----------

3. Was expecting closure will require a single argument, which is tuple;
but it accepts even just x, y

typealias IntInt = (Int,Int)

func foo(block: (IntInt) -> Void) {
    let z : IntInt = (1,2)
    block(z)
}

foo { x in print(x)} // ok
foo { x, y in print(x,y)}
foo { (x, y) in print(x, y)}

I'm not sending two values to closure, I send one instance which is tuple.

Shouldn't we add consistency in Swift regarding allowed argumets of closure
if tuple is required as parameter?