Swift - Assigning Overloaded Function to Variable - swift

I am getting a compile time error that myFunc reference is ambiguous.
func f (s: String) -> String { return "version 1: " + s }
func f(sourceString s: String) -> String { return "version 2: " + s }
var myFunc: (String)-> String = f as (sourceString : String)->String
How can I explicitly reference each version of the overloaded function, f, in the example above? If I comment out either declaration of func f it will compile and work. But I would like to know how to reference each of the functions if both are declared. Thanks.

I don't know how to do exactly what you want, but maybe this helps:
var myFunc1: (String)-> String = { s in f(sourceString: s) }
var myFunc2: (String)-> String = { s in f(s) }
You can now call:
let s1 = myFunc1("one") // returns "version 2: one"
let s2 = myFunc2("two") // returns "version 1: two"

Interesting one this. I don’t think it’s possible without doing something along the lines of #marcos’s suggestion. The problem you is you can “cast away” the names in tuples:
let named_pair = (s: "hello", i: 1)
named_pair.s // hello
let anon_pair = named_pair as (String,Int)
// or anon_pair: (String,Int) = named_pair, if you prefer
anon_pair.s // no such member 's'
Now suppose you define two functions, identical except one has named arguments:
func f(s: String, i: Int) { println("_: \(s)") }
func f(#s: String, #i: Int) { println("s: \(s)") }
You can then call it via tuples with named vs unnamed arguments:
f(named_pair) // prints s: hello
f(anon_pair) // prints _: hello
// but if you try to call a named argument function with unnamed tuples:
func g(# s: String, # i: Int) { println("s: \(s)") }
g(anon_pair) // compiler error
let h = g
h(anon_pair) // compiler error
h(named_pair) // works
But because you can cast away these names you can do this:
// compiles and runs just fine...
(g as (String,Int)->())(anon_pair)
let k: (String,Int)->() = g
// as does this
k(anon_pair)
And this ability to do this means it’s not possible to use a type to disambiguate an function overloaded only by argument names, as far as I can tell.

Referencing func f (s: String) -> String { return "version 1: " + s }:
let myFunction = f(s:)
Referencing func f(sourceString s: String) -> String { return "version 2: " + s }:
let myFunction = f(sourceString:)
Referencing func anotherFunction(_ param: Any) {}:
let myFunction = anotherFunction(_:)
If you haven't overloaded the function, you don't need to explicity write out the parameter names when referencing the function.

Number of arguments should vary.
If the number of arguments are same then their data types should
vary.
Example
func f(x : String) -> NSString {
return a
}
func f(x : UInt) -> NSString {
return "{\(x)}"
}

I don't think you can. You can call one or the other:
println(f("test")) // version 1: test
println(f(sourceString: "test")) // version 2: test

Related

Spread variable parameter count on generic function

In javascript it is pretty easy to take a variable count of arguments and pass it to a sub function without the need to modify the sub function. For example, you want to write a wrapper function which takes a generic function as first argument and calls it with the rest of the arguments:
function wrapper(func, ...args) {
return func(...args)
}
I want to archive something similar in swift. There I have many many c function which I want to wrap with another function for some safety reasons.
Now I have two major road blockers:
The first one: I don't know how to do something like func(...args) in swift. This is why I temporary tried this:
private func apply<ReturnValue, FunctionParams>(_ fun: (_ params: FunctionParams...) -> ReturnValue, _ paramsPass: [FunctionParams]) throws -> ReturnValue {
switch paramsPass.count {
case 0:
return fun()
case 1:
return fun(paramsPass[0])
case 2:
return fun(paramsPass[0], paramsPass[1])
case 3:
return fun(paramsPass[0], paramsPass[1], paramsPass[2])
case 4:
return fun(paramsPass[0], paramsPass[1], paramsPass[2], paramsPass[3])
case 5:
return fun(paramsPass[0], paramsPass[1], paramsPass[2], paramsPass[3], paramsPass[4])
case 6:
return fun(paramsPass[0], paramsPass[1], paramsPass[2], paramsPass[3], paramsPass[4], paramsPass[5])
default:
throw NSError(domain: "apply", code: paramsPass.count, userInfo: nil);
}
}
This is not really good and only works for a max parameter count of 6.
The second road blocker is, I am not able to write the required swift types to archive something like I described. This is what I tried:
private func runUnsafeFunction<ReturnValue, FunctionParams>(_ fun: (_ params: FunctionParams...) -> ReturnValue, _ paramsPass: FunctionParams...) throws -> ReturnValue {
// wrapper code
return try apply(fun, paramsPass)
}
However, if I try to call it, I get: Generic parameter 'ReturnValue' could not be inferred
Probably I miss something here. But at this point I am stuck.
Why not pass the function and its arguments in a closure?
func runUnsafeFunction<ReturnValue>(function: () -> ReturnValue) -> ReturnValue {
// do stuff
return function()
}
Example
func add(_ a: Int, _ b: Int) -> Int {
a + b
}
func add(_ a: Int, _ b: Int, _ c: Int) -> Int {
a + b + c
}
let result = runUnsafeFunction { add(3, 4) }
let result2 = runUnsafeFunction { add(3, 4, 5) }

Creating an enum instance

suppose I have
enum Example {
case one(string: String)
case two(string: String)
}
and now I have
let x = Example.one(string: "Hello")
The question:
let y = ?
how do I create another instance of the same enum in e, so that I end up with y == .one("World"))
The types of enum cases with associated values are closures with arguments corresponding to the type of the associated values, and with a return corresponding to the type of the enum (with the value of the return being the specific case). I.e., for your example above, the type of Example.one as well as Example.two is (String) -> Example, where the closures expressed by these two cases yield different results; instances of .one(...) and .two(...), respectively.
Hence, instead of writing your own method to "clone" a given case, you could simply have a computed property which returns the already existing closures Example.one and Example.two (if self is one or two, respectively), which can subsequently be invoked upon a String argument to construct a new Example instance (with value .one or .two; along with the supplied associated String value).
E.g.:
enum Example {
case one(string: String) // type: (String) -> Example
case two(string: String) // type: (String) -> Example
var caseClosure: (String) -> Example {
switch self {
case .one: return Example.one
case .two: return Example.two
}
}
}
let x = Example.one(string: "Hello") // .one("Hello")
let y = x.caseClosure("World") // .one("World")
However, since all the cases in your example are closures of the same type, namely (String) -> Example (i.e. have the same number and type(s) of associated values), you might as well, as already proposed in a comment by #Hamish, wrap an enum with no associated values in a struct along with the always-String "associated value" a separate member of the struct. E.g. expanding Hamish's example with some initializers:
struct S {
enum E {
case one
case two
}
var e: E
var string: String // Since "associated value" is always the same type
init(_ e: E, string: String) {
self.e = e
self.string = string
}
init(from s: S, string: String) {
self.e = s.e
self.string = string
}
}
let x = S(.one, string: "Hello")
let y = S(from: x, string: "World")
let z = S(x.e, string: "World")
You do that by calling the Initializer exactly like you did for x:
enum Example {
case one(string: String)
case two(string: String)
}
let x = Example.one(string: "Hello")
print(x) // Prints one("Hello")
let y = Example.one(string: "World")
print(y) // Prints one("World")
Also, The , in your enum declaration is wrong and has to be removed.
UPDATE:
The comment explained the question in more detail, so here is my updated answer:
An elegant way to solve this is to use a function on the original enum type Example.
enum Example {
case one(string: String)
case two(string: String)
func cloneWith(string: String) -> Example {
switch self {
case .one:
return .one(string: string)
case .two:
return .two(string: string)
}
}
}
let x = Example.one(string: "Hello")
print(x) // Prints one("Hello")
let y = x.cloneWith(string: "World")
print(y) // Prints one("World")

How to use generic function to tear down swift's optional pyramid of doom

Instead of using multiple optional bindings, we can define a function to tear down optional pyramid of doom.
func if_let<T, U, V> (a: T?, _ b: U?, _ c: V?, fn:(T, U, V) -> () ){
if let a = a {
if let b = b {
if let c = c {
fn(a, b, c)
}
}
}
}
Then I can write like this:
var s1: String? = "s11"
var s2: String? = "s22"
var s3: String? = "s33"
if_let(s1, s2, s3) { s1, s2, s3 in
print(("\(s1) - \(s2) - \(s3)"))
}
However, the problem is how to make this if_let function more generic so that it can accept any number of arguments. My implementation is like this:
func if_let<T> (values: T?..., fn:(params: [T]) -> ()) {
for value in values {
guard value != nil else { return }
}
let unwrappedArray = values.map{ $0! }
fn(params: unwrappedArray)
}
I tried to map the array and get a new one with all elements unwrapped and then call the fn. But when I ran the test again, I got a compile error:
Cannot convert value of type String? to expected argument type '_?'
Can anyone explain and fix this error?
The problem is that your second implementation of if_let no longer takes as a final parameter a function of type (T,U,V)->(). It now needs a function of type ([T])->(). If you call it with one, it compiles:
if_let(s1, s2, s3) { args in // or: (args: [String])->() in
print("\(args[0]) - \(args[1]) - \(args[2])")
}
A relevant note, rather than an answer to the specific question: with Swift 2, you needn't enter the pyramid of doom no more
let a: String? = nil
let b: Int? = nil
let c: Double? = nil
// possible mutate...
if let a = a, b = b, c = c {
// do something with shadow vars
}

Swift Array of Functions

I'm very new to Swift, but slowly learning by following the Stanford iTunes U course. I have a question about storing and calling functions in an array.
The code I have (below) seems to store the function properly, but when I try to call one of the functions I get this error: '(IntegerLiteralConvertible, IntegerLiteralConvertible) -> $T6' is not identical to (String, Op).
I found this answer that was helpful in getting to where I am, but now I'm stuck.
enum Op {
case binary((Double, Double) -> Double)
}
var ops = [String: Op]()
func addOperation(symbol: String, op: Op) {
ops[symbol] = op
}
addOperation("×", Op.binary(*))
addOperation("÷", Op.binary({ $1 / $0 }))
addOperation("+", Op.binary(+))
addOperation("−", Op.binary({ $1 - $0 }))
var newValue = ops["÷"](6, 3) // Produces the error
My understanding was that ops["÷"] should be the function I stored in the array earlier. Am I not calling it properly?
#Nate Cook answer is corret but why do you have to use enum in this case? Consider using typealias like following :
var ops = [String: Op]()
func addOperation(symbol: String, op:Op) {
ops[symbol] = op
}
addOperation("×", (*))
addOperation("÷", ({ $1 / $0 }))
addOperation("+", (+))
addOperation("−", ({ $1 - $0 }))
var newValue = ops["÷"]?(3,6)
// you have to put this outside of any class
public typealias Op = (Double, Double) -> Double
You have two problems there. First, subscripting a dictionary returns an optional value, so ops["÷"] is an Op? that needs to be unwrapped before you can use it.
Second, the associated value of an enum can't be accessed directly—you can only get the value when pattern matching in a switch statement. I'd suggest adding a computed property to Op that does the work for you:
enum Op {
case binary((Double, Double) -> Double)
var binaryCall: ((Double, Double) -> Double)? {
switch self {
case let .binary(operation):
return operation
}
}
}
Then you would call it like this instead:
var newValue = ops["÷"]?.binaryCall?(6, 3)
// Optional(0.5)
An alternate method of implementation would be to just build an dictionary of binary operations, like so (you still need to unwrap once, though):
typealias BinaryOp = (Double, Double) -> Double
var binaryOps: [String: BinaryOp] = [:]
binaryOps["×"] = { $0 * $1 }
binaryOps["÷"] = { $1 / $0 }
newValue = binaryOps["÷"]?(6, 3)

Why do curried functions require external parameter names?

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)