Understanding closure syntax in Swift
If you're just getting started with the Swift programming language, you may have read or heard the word closure getting thrown around a lot.
If you've spent some time working with iterators like map
, you've already been using them. e.g.
// define an array
let someArray = [7,3,2,6,4,8,3,9]
// add one to each element
someArray.map({$0 + 1})
// print out a concatenated string
print(someArray.map({"\($0) cakes"}))
// perform other operations
let otherArray = someArray.map({ item in
(7*item + 4) * 3
})
This concise writing style can often cloud what is going on behind the scenes, so in this short post, we'll work through an example to motivate how we got to this abbreviated style.
Let's take a simple example of a function written in Swift, that takes as input two integers numberA
and numberB
, and a callback operation
.
func calculator(numberA: Int, numberB: Int, operation: (Int, Int) -> Int) -> Int {
return operation(numberA, numberB)
}
When writing functions that take another function (or callback) as an argument, rather than writing the expected argument as an explicit named function
func addOperation(nA: Int, nB: Int) -> Int {
return nA + nB
}
and calling it like
calculator(numberA: 8, numberB: 3, operation: addOperation)
we can pass it as an anonymous function (or closure) instead
calculator(numberA: 8, numberB: 3, operation: { (nA: Int, nB: Int) -> Int in
return nA + nB
})
We can now iterate on this first pass, and simplify in a number of ways.
- We can remove the unnecessary return statement
calculator(numberA: 8, numberB: 3, operation: { (nA: Int, nB: Int) -> Int in
nA + nB
})
- Drop the closure argument label
calculator(numberA: 8, numberB: 3) { (nA: Int, nB: Int) -> Int in
nA + nB
}
- Allow swift to infer the types
calculator(numberA: 8, numberB: 3) { (nA, nB) -> Int in
nA + nB
}
calculator(numberA: 8, numberB: 3) { (nA, nB) in
nA + nB
}
calculator(numberA: 8, numberB: 3) { (nA, nB) in nA + nB }
- Finally we can use anonymous arguments to rewrite
calculator(numberA: 8, numberB: 3) { (nA, nB) in nA + nB }
more concisely as
calculator(numberA: 8, numberB: 3) { $0 + $1 }
From this point, we can see how this can easily be extended to other operations
calculator(numberA: 6, numberB: 5) { $0 - $1 }
calculator(numberA: 9, numberB: 23) { $0 * $1 }
calculator(numberA: 15, numberB: 4) { $0 / $1 }