Swift Closures

Photo by Dave / Unsplash

I will kickstart a series of small posts about my recent founded passion on the Swift language by talking a bit about swift closures.

Quite briefly a closure is self-contained block of code that can be stored and passed around as any other type:

var simpleClosure = {
    print("Hello from a closure!")
}

simpleClosure()

These closures can store the references to any variables from the context where they are created and swift will handle all the memory management over them.

They can as well capture values from enclosing closures:

var wrapperColosure = {
    let outerVariable = "Jon"
    let innerClosure = {
        print("Hello \(outerVariable)!")
    }
    
    innerClosure()
}

wrapperColosure()

As any other function, a closure can as well accept paramenteres, but as an anonymous function we can use the in keywork to allow it to do so. A bit simillar with the arrow on ecmascript:

var greeterClosure = {(name: String) -> String in
    "Hello \(name)!"
}

greeterClosure("Jon")

We can of course as well return values from closures by simply defining the return type such as:

var doubleAmount = {(number: Int) -> Int in
    number * 2
}

print(doubleAmount(2))

For a specific function, that accepts a closure as a parameter, if we define the closure argument as the last one we can as well use some syntax sugar to directly pass the block of code such as:

func computation(n: Int, closure: (_ num: Int) -> Int) {
    print("The original value is \(n)")
    print("We apply a extra computation...")
    let newValue = closure(n)
    print("We end our computation: \(newValue)")
}

computation(n: 2) { (num: Int) -> Int in
    num + num
}
```

As the Swift compiler will be able to infer the types based on the definition on computation we can then even make it implicit as such:

computation(n: 3) { num in
    num * 3
}

And if we wanna go even more "cryptic", we can use the syntax $0, $1, ..$n for multiple arguments, based on their order and ommit from the block declaration:

computation(n: 4) {
    $0 * 4
}

To fully grasp the power of closures we can use all the concepts exposed above and use the notion of closure and the access to the enclosing scopes to do for example functions that return scopes and hold some specific state:

func multiply(multiplier: Int) -> (Int) -> Int {
    let mul = multiplier
    
    return { num in
        return mul * num
    }
}

var timesTwo = multiply(multiplier: 2)
print(timesTwo(5))

var timesTen = multiply(multiplier: 10)
print(timesTen(5))

You can find the playground for this small article at: https://gist.github.com/josetapadas/98c133674ec7d8dc0099e8bf2a827d41

josé tapadas alves

josé tapadas alves

🪐 Recovering Telecommunications engineer and software tinkerer. Passionate Rubyist and JavaScript zealot. Nature, music and life enthusiast 🌱