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 {
...
}
Related
Given:
class Elem {
func f() -> AnotherElem {
return AnotherElem(elem: self)
}
}
I want to call the map function on array of Elems passing the function f:
Sample code:
collection.map { $0.f() }
However, I don't like this {} notation so I was thinking whether or not I can pass a function as an argument (which in my eyes increases readability), and indeed I can
What I want is to do the following:
collection.map(Elem.f)
The last is valid syntax however the type of the array is the following: [() -> AnotherElem] instead of expected [AnotherElem] type.
Is a bug or a feature?
Obviously, this could be solved by calling map again and calling the array of blocks, but this is not the problem I'm having.
I'm struggling to understand why it is the way it is
This is expected behaviour, i.e. not a bug.
If you try to use an instance method someMethod of the form(T) -> U directly like this:
SomeType.someMethod
The type of that expression is (SomeType) -> (T) -> U. In your case, The type of Elem.f is (Elem) -> () -> AnotherElem.
Why is it designed like this? It is so that you can pass an instance to SomeType.someMethod, and then get the original instance method:
let f = SomeType.someMethod(instanceOfSomeType)
I guess this could be somewhat called "currying".
Anyway, you would need another function to transform Elem.f:
func uncurry<T, U>(_ f: #escaping (T) -> () -> U) -> (T) -> U {
return { f($0)() }
}
Now passing uncurry(Elem.f) will work.
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.
I was writing some example code in a playground and wanted a function that returns the distance between two values, both of which conform to the Strideable protocol in Swift so that I could use the distance(to other: Self) -> Self.Stride function. My implementation was as follows:
func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U
{
return a.distance(to: b)
}
After observing this function for a while, I realized that I wasn't sure which Stride was being used in the where clause, the one from a or from b. From what I understand it would be possible for a and b to define different associated types for Stride. Also I haven't made any statements to ensure that a.Stride == b.Stride, although I understand that I could expand my where clause to do so.
So, which one would get used to check equivalence to U? To be clear, the question isn't about this particular code block, but rather any situation in which this ambiguity would exist.
a and b are the same type. If you wanted them to be different Strideable types you would add another generic parameter conforming to Strideable such that the function signature appears as follows:
func bar<T: Strideable, V: Strideable, U>(_ a: T, to b: V) -> U where T.Stride == U, V.Stride == U {
return a.distance(to: a) //Trivial return statement (see explanation below)
}
Although the aforementioned code would compile, return a.distance(to: b) would not compile because they (a and b) are different types and the definition of distance in Swift3 is public func distance(to other: Self) -> Self.Stride (note the use of Self which restricts other to the same type as the Strideable upon which this function is called). In conclusion, although you could make a and b different types, for your application it would not make sense to do so.
As further evidence for not being able to call your original posted code with different types please see the attached
Playground screenshot which shows an error when using different types.
However, this works fine in the playground.
func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U {
return a.distance(to: b)
}
let doubleFoo: Double = 4.5
let intFoo: Double = 4
let g = distanceFrom(doubleFoo, to: intFoo) // gives me a double of -0.5
I hope this helps.
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).
Given this simple currying function:
func foo(x:Int)(y:Int)->String{
return "\(x) with \(y)"
}
I'd expect to be able to do something like this:
let bar = foo(1)
bar(2) //<- error: Missing argument label 'y:' in call
If I label the call to bar (as in bar(y:2)) everything works fine. But I don't understand why the parameter name is necessary. Is there any way to avoid it?
The obvious thing:
func foo(x:Int)(_ y:Int)->String ...
does not seem to work.
It's a bug, you should file a radar at bugreport.apple.com
As a confirmation, if you place an underscore, like this
func foo(x: Int)(_ y: Int) -> String
you get a warning
Extraneous '_' in parameter: 'y' has no keyword argument name
So it explicitly says that y has no external name, but it still requires one when called, which is clearly against the language specification.
I believe it is a compiler bug, your example should work as described in The Swift Programming Language book where they mention declaring curried functions:
func addTwoNumbers(a: Int)(b: Int) -> Int {
return a + b
}
addTwoNumbers(4)(5) // Returns 9
https://bugreport.apple.com
good find!
I am not sure I fully understand your currying. Here is my take on it. I have a function foo as follows:
func foo(x:Int, y:Int) -> String{
return "\(x) with \(y)"
}
let bar = foo(1, 2) // gives "1 with 2"
I wish to curry this function to 'fix' the value for x, so do so as follows:
func fooCurry(x:Int) -> (Int -> String) {
func curry(y:Int) -> String {
return foo(x, y)
}
return curry
}
The above returns a new function which can be used as follows:
let curriedFoo = fooCurry(1)
let barWithCurry = curriedFoo(2) // gives "1 with 2"
The function returned by fooCurry has the signature (Int -> String), which means that the parameter does not have an external name.
Not the best syntax, but if you want to get around it for now, you can use the following for basic curried functions:
func foo(x:Int) -> Int -> String {
return {
return "\(x) with \($0)"
}
}
Then you can just do:
let bar = foo(1)
bar(2) //-> 1 with 2
Now obviously the problem with this becomes obvious when you want to write a curried function for piping four Ints for example:
func makerAdders(a:Int)(b:Int)(c:Int)(d:Int) {...}
becomes like this:
func add(a:Int) -> Int -> Int -> Int -> Int {
return {
b in return {
c in return {
d in return a + b + c + d
}
}
}
}
The inner closures make it a bit better than using inner functions, but again it defeats the purpose of the nice func add(a:Int)(b:Int)(c:Int)(d:Int) {return a+b+c+d} syntax.
Definitely a bug in the compiler as far as I can tell. Until it's fixed you can get a properly curried version of any function using these functions (note that I've included cases for two and three arguments, extend at your leisure:
func curry<A,B,C>(f: (A, B) -> C) -> A -> B -> C {
return { a in { b in return f(a,b) } }
}
func curry<A,B,C,D>(f: (A, B, C) -> D) -> A -> B -> C -> D {
return { a in { b in { c in return f(a,b,c) } } }
}
Just use:
curry(addTwoNumbers)(1)(2)