I am trying to migrate my code from xcode 8.2 swift 3.0.2 to xcode 9 swift 4, and I have problem with this code:
func test<T0, TRet>(_ fn: (T0) -> TRet) -> Void {
print("foo1")
print(T0.self)
}
func test<T0, T1, TRet>(_ fn: (T0, T1) -> TRet) -> Void {
print("foo2")
print(T0.self)
print(T1.self)
}
let fn2 : (Int, Int) -> Int = { (x:Int, y:Int)->Int in
return x+y
}
test(fn2)
xcode 8.0.2, swift 3.0.2 results with:
foo2
Int
Int
xcode 9, swift 4 results with:
Playground execution failed:
error: MyPlayground.playground:12:1: error: ambiguous use of 'test'
test(fn2)
^
MyPlayground.playground:1:6: note: found this candidate
func test<T0, T1, TRet>(_ fn: (T0, T1) -> TRet) -> Void {
^
Am I missing something? Is there any new feature in swift 4 that causes this error?
Update
I filed a bug at bugs.swift.org as suggested in the comments.
https://bugs.swift.org/browse/SR-6108
I ran into the same problem, and stumbled across a workaround that is (for my purposes) nicer than disambiguating via naming. Perhaps it is not even a workaround, just the way things have to be. It's also possible that this is newly-possible in Swift 4.1 (not sure, since I migrated directly from Swift 3 to 4.1)
Change this:
func test<T0, TRet>( fn: (T0) -> TRet) -> Void
...to this...
func test<T0, TRet>( fn: ((T0)) -> TRet) -> Void
(note the extra pair of parens around the T0 callback parameter, which explicitly makes it into a tuple-of-1)
After this change, test(fn2) compiles and calls the test<T0,T1,TRet> overload.
It seems that the compiler is able to treat a function with N arguments as a function with one N-way-tuple argument. Hence, both the (T0) -> TRet and (T0,T1) -> TRet overloads are candidates for fn2, and the call is ambiguous. Adding 2nd pair of parens ((T0)) -> TRet limits that overload to an argument with a single parameter or 1-way tuple.
Related
Please consider the following code:
protocol P {}
class X {}
class Y: P {}
func foo<T>(_ closure: (T) -> Void) { print(type(of: closure)) }
func foo<T>(_ closure: (T) -> Void) where T: P { print(type(of: closure)) }
let xClosure: (X?) -> Void = { _ in }
foo(xClosure) // prints "(Optional<X>) -> ()"
let yClosure: (Y?) -> Void = { _ in }
foo(yClosure) // prints "(Y) -> ()"
Why does the foo(yClosure) call resolve to the version of foo constrained to T: P?
I understand why that version prints what it prints,
what I don't see is why it gets called instead of the other one.
To me it seems that the non-P version would be a better match for T == (Y?) -> Void.
Sure, the constrained version is more specific, but it requires conversion
(an implicit conversion from (Y?) -> Void to (Y) -> Void),
while the non-P version could be called with no conversion.
Is there a way to fix this code in a way such that the P-constrained version gets called
only if the parameter type of the passed-in closure directly conforms to P,
without any implicit conversions?
Specificity seems to always trump variance conversions, according to my experiments. For example:
func bar<T>(_ x: [Int], _ y: T) { print("A") }
func bar<T: P>(_ x: [Any], _ y: T) { print("B") }
bar([1], Y()) // A
bar is more specific, but requires a variance conversion from [Int] to [Any].
For why you can convert from (Y?) -> Void to (P) -> Void, see this. Note that Y is a subtype of Y?, by compiler magic.
Since it is so consistent, this behaviour seems to be by design. Since you can't really make Y not a subtype of Y?, you don't have a lot of choices if you want to get the desired behaviour.
I have this work around, and I admit it's really ugly - make your own Optional type. Let's call it Maybe<T>:
enum Maybe<T> {
case some(T)
case none
// implement all the Optional methods if you want
}
Now, your (Maybe<Y>) -> Void won't be converted to (P) -> Void. Normally I wouldn't recommend this, but since you said:
in the real-world code where I encountered this, the closure has multiple params, any of them can be optional, so this would lead to a combinatorial explosion.
I thought reinventing Optional might be worth it.
I've the following generic function (not part of any class):
func execFuncWithGenericParameter<T, U>(f: (T) -> U){
print(f("Hello World"))
}
I'd like to call this function in with a closure like this:
execFuncWithGenericParameter(f: { (p: String) -> Int in
print(p)
return 4711
})
But the compiler (iPad Swift Playground) tells me that "(String) -> U is not convertible to (T) -> U".
Naturelly I've done done some investigation and was the opinion that the Compiler automatically will infer the types.
Thanks.
The types are being inferred as far as the nature of f: (T) -> U is concerned. The problem is the call to f inside your first method.
Ask yourself: what if T were not String? Then f("Hello world") would be illegal. That is the quandary you've left the compiler with — and it rightly refuses to deal with it.
Here's a legal version:
func execFuncWithGenericParameter<T,U>(f: ((T) -> U), param:T){
f(param)
}
execFuncWithGenericParameter(f: { (p: String) -> Int in
print(p)
return 4711
}, param:"Hello")
Now the first method knows that param will be a T, so all is well. And in the second method, when we call the first method, T is String and param is a String, so it compiles (and runs, and prints).
This question already has an answer here:
What is the cause of this type error?
(1 answer)
Closed 6 years ago.
I have the following code in a 'SquareMatrix <T: HasZeroOne>' class whose data 'data' is stored in a [[T]] double array. I made this mapping function to mimic the standard Swift one.
public func map<S: HasZeroOne>(transform: (T) -> S) -> SquareMatrix<S> {
return SquareMatrix(data: data.map{(row: [T]) in row.map({(col: T) in transform(col)})})!
}
At first I tried the simpler syntax:
public func map<S: HasZeroOne>(transform: (T) -> S) -> SquareMatrix<S> {
return SquareMatrix(data: data.map{$0.map(transform)})!
}
But got the following error in both cases:
Cannot convert value of type '(T) -> S' to expected argument type '(_) -> _'
I'm completely lost. What have I done wrong?
As is always the way, I got an answer 5 minutes later. Not that the error message helped at all. The following works:
public func map<S: HasZeroOne>(transform: (T) -> S) -> SquareMatrix<S> {
return SquareMatrix<S>(data: data.map{$0.map(transform)})!
}
Note the <S>.
Hope someone finds this a useful hint!
The following example expands upon the example shown in this swift-evolution link, which describes only one parameter per argument list. Any suggestion on how to fix a two parameter argument list?
// Before: (yields warning)
func curried(x: Int)(y: String, z:String) -> Float {
return Float(x) + Float(y)! + Float(z)!
}
// After: (this is not working)
func curried(x: Int) -> (String, String) -> Float {
return {(y: String, z: String) -> Float in
return Float(x) + Float(y)! + Float(z)!
}
}
Xcode 7.3 still reports the second method as "Curried function declaration syntax will be removed in a future version of Swift; use a single parameter list."
Any help appreciated.
Ignore the Xcode 7.3 warning about the second version. If you clean out the build folder, the warning will probably go away. More important, the second version does work — it compiles in Swift 3, which is all that matters.
I am unable to understand the following method signature I went through lastly while working on an open source framework:
public func myFunc<A: TypeOfA, B: TypeOfB, C: TypeOfC>
(someA: A)
-> (someB: B)
-> ReturnedType {
// BODY OF THE FUNC
}
Why is there 2 return arrows '->'? Does anyone know where I could get more info about this syntax? Did find anything in the Apple Swift doc.
I am NOT talking about the generics but about the way the parameters are declared.
And yes this compiles fine with xcode 7.3
Thanks
The function takes one argument, someA: A, and returns another function.
The function it returns takes someB: B and returns ReturnedType.
This is equivalent to:
public func myFunc<...>(someA: A) -> ((someB: B) -> ReturnedType) {
...
}
or
typealias SecondFunction = (someB: B) -> ReturnedType
public func myFunc<...>(someA: A) -> SecondFunction {
...
}