Logo 61e73bc61c0e1780102320e879dc3cac0e29303ea8894dd8f10c942f3ba8120f

otters.io

An adorable little blog

A Little Less Spice in Swift 3

Sunday — April 17th, 2016

Curry

Swift 3 is scheduled to be released in late 2016. Which, by Apple time, means whenever is least convenient after August. If you’ve been riding the Swift train for a while then you are probably no stranger to breaking changes between releases. Most of the time, Xcode can automatically convert your old Swift code to the new syntax and Swift 3 promises to finally stabilize the ABI. But, if you have Swift 2 code you’ll need to make a few edit when you jump aboard Swift 3.

If you’re really Swift-savvy then you may have been using some function currying. Currying is awesome if you know what currying is. If you don't then you’ll enjoy scratching your head at magical function calls that look something like this:

multiply(3)(4) // returns 12

This sort of thing looks really weird for anyone who doesn’t sleep next to a “Haskell 4 Life” poster. This sort of function makes a lot of sense in the context of Functional programming with Ranges and Closures in Swift. For example, this:

let timesTwo = multiply(2)
let numbers = 1...100
let biggerNumbers = numbers.map(timesTwo)
// biggerNumbers = [2, 4, 6, 8, ... 200]

is easier to read than this:

let numbers = 1...100
let biggerNumbers = numbers.map { multiply($0, 2) }
// biggerNumbers = [2, 4, 6, 8, ... 200]

Writing a curried function is actually quite easy in Swift 2. You just write a function with a few more parenthesis like this:

func multiply(x: Int)(y: Int) -> Int {
    return x * y
}

Unfortunately, this syntax magic must go away. The proposal to remove currying as we know it has been accepted for Swift 3 and is now awaiting implementation.

The main reason for dropping the current currying syntax is because it messes with var and inout argument annotations. Currying is no problem if you just want to pass a copy of your data into a function and receive a copy of the result back. When you want to pass in mutable references to existing variables with var or you want to get that reference back with inout, then life gets complicated. (If you’re familiar with C, using var or inout is similar to passing by reference with *parameterName) This is where Swift comes to terms with its C++ roots and its functional aspirations.

Luckily there is a replacement for any of your existing curried functions. Instead of writing a curried function using two sets of parameters, you can write a function that returns a function. It’s a few more keystrokes than the currying you used to know but it gives the same result. The change looks something like this:

// Before:
func multiply(x: Int)(y: Int) -> Int {
    return x * y
}

// After:
func multiply(x: Int) -> (Int) -> Int {
    return { (y: Int) -> Int in
        return x * y
    }
}

You can replace your existing curried functions with the new syntax today and be ahead of the curve. If you haven’t written any curried functions yet, I highly recommend trying it out.