Optional trailing closures #swiftlang

Question: Can I set an optional trailing closure in a function?

Answer: Easiest way is to use a non-optional default value.

func doSomethingWithCompletion(completion: () -> Void = {}) {
    // ... Do Something ...
    completion()
}

This popped up in a conversation yesterday and naturally the discussion then verged onto how efficient or inefficient this approach is over, say, passing an optional closure value, e.g. (() -> Void)?.

So after running a few tens of millions of iterations on several approaches, the results were pretty interesting:

func test1(c : () -> Void) {c()}
func test2(c: (() -> Void)?) {
    if let c = c {c()}
}
func test3(c: (() -> Void)?) {c?()}
func test4(c: () -> Void = {}) {c()}

In unoptimized runs, both test1 and test4 massively out-performed test2 and test3 by an order of magnitude on 10 million increments of a local variable.

test1
Elapsed time: 0.134177029132843
After tests: 10000000
test2
Elapsed time: 1.11247903108597
After tests: 20000000
test3
Elapsed time: 0.944562971591949
After tests: 30000000
test4
Elapsed time: 0.146546959877014
After tests: 40000000
Program ended with exit code: 0

 

Using whole module optimization, the latter three are more or less equal but the first, without default values or optionals, still runs much faster.

test1
Elapsed time: 0.00389701128005981
After tests: 10000000
test2
Elapsed time: 0.0398470163345337
After tests: 20000000
test3
Elapsed time: 0.0474460124969482
After tests: 30000000
test4
Elapsed time: 0.0474919676780701
After tests: 40000000
Program ended with exit code: 0

If you’re going to supply arguments, make sure you use an in-clause for the default no-op closure, e.g. {_ in} or {(_) in}, etc.

One Comment

  • I’m actually more curious about the reasoning behind your answer to the actual question… 🙂 Why is specifying a default value considered easiest? Is it because you don’t have to specify `nil` when no closure is needed? Is it because calling the closure doesn’t have to use a question mark (`completion?()`)?