Chris Gregg
Chris Gregg

Reputation: 2382

Cannot translate Swift 2.2 currying to future Swift format

I have the following curried function and I received an Xcode warning that Curried function syntax will be removed in a future version of Swift; use a single parameter list, but the suggested fix-it didn't work (it simply combined the parameters into one function call). I am trying to convert to the new format, but I don't understand how it works. The beginFetchWithCompletionHandler function below expects handleDownload to have the parameter signature of (data : NSData?, error : NSError?).

fetcher.beginFetchWithCompletionHandler(handleDownload)

I want to also pass in an integer, as follows:

fetcher.beginFetchWithCompletionHandler(handleDownload(0))

The following curried function works perfectly (but gives the warning):

func handleDownload(iCount : Int)(data : NSData?, error : NSError?) -> Void {
    print(iCount)
    print(data!.length)
}

Here is what I've tried, but I get the error, "Expression resolves to an unused function":

func handleDownload2(iCount:Int) -> (NSData?, NSError?) -> Void {
    return { (data: NSData?, error: NSError?) -> Void in {
            // received image
            print(iCount)
            print(data!.length)
        }
    }
}

Upvotes: 3

Views: 183

Answers (2)

Imanou Petit
Imanou Petit

Reputation: 92459

The Swift Evolution proposal SE-0002 - Removing currying func declaration syntax that was accepted states:

We remove support for multiple argument patterns in func declarations, reducing the grammar for func-signature to allow only one argument clause. For migration purposes, existing code that uses currying declaration syntax can be transformed to explicitly return a closure instead:

  // Before:
  func curried(x: Int)(y: String) -> Float {
    return Float(x) + Float(y)!
  }

  // After:
  func curried(x: Int) -> (String) -> Float {
    return {(y: String) -> Float in
      return Float(x) + Float(y)!
    }
  }

Thus, the answer given by Martin R in order to solve your code is correct:

func handleDownload2(iCount: Int) -> (NSData?, NSError?) -> Void {
    return { (data: NSData?, error: NSError?) -> Void in
        // received image
        print(iCount)
        print(data!.length)
    }
}

Note, however, that you can be more concise:

func handleDownload2(iCount: Int) -> (NSData?, NSError?) -> Void {
    return { (data, error) in
        // received image
        print(iCount)
        print(data!.length)
    }
}

Here, the type of data and error is implicitly given by the return type of your handleDownload2 function: (NSData?, NSError?) -> Void.


Although I would not recommend it for readability matters, your code can be even more concise by using shorthand argument names:

func handleDownload2(iCount: Int) -> (NSData?, NSError?) -> Void {
    return {
        // received image
        print(iCount)
        print($0!.length)
    }
}

Furthermore, I sometime try to be explicit when I use closures as it helps me set quickly the correct return type for them:

func handleDownload2(iCount: Int) -> (NSData?, NSError?) -> Void {
    let innerBlock: (NSData?, NSError?) -> Void = { (data, error) in
        // received image
        print(iCount)
        print(data!.length)
    }
    return innerBlock
}

Upvotes: 1

Martin R
Martin R

Reputation: 539795

The inner curly braces are wrong, it should be:

func handleDownload2(iCount:Int) -> (NSData?, NSError?) -> Void {
    return { (data: NSData?, error: NSError?) -> Void in
        // received image
        print(iCount)
        print(data!.length)
    }
}

Upvotes: 2

Related Questions