Swift Tip: Without Actually Escaping

In Swift Talk 90, we wrote a concurrent implementation of map. The interface looks like this:

extension Array {
    func concurrentMap<B>(_ transform: @escaping (Element) -> B) -> [B] {
        // ...

The transform function is marked as @escaping (the compiler automatically infers this for us). However, even though the transform function is used in a queue, it’s not actually escaping: the function isn’t used or referenced after the concurrentPerform returns. Ashton Williams sent us a tweet:

In addition to handling throws like you mentioned, this parallelMap function could also use withoutActuallyEscaping(_:do:) to remove escaping from its own signature

His suggestion definitely cleans up the interface, and is generally a good idea in cases where the compiler thinks the closure is escaping, but the closure isn’t actually escaping.

However, after looking at our code some more, we found that the @escaping parameter was an artifact of a previous version (before refactoring). It turns out that we can remove @escaping without having to use withoutActuallyEscaping(_:do:):

extension Array {
    func concurrentMap<B>(_ transform: (Element) -> B) -> [B] {
        let result = ThreadSafe(Array<B?>(repeating: nil, count: count))
        DispatchQueue.concurrentPerform(iterations: count) { idx in
            let element = self[idx]
            let transformed = transform(element)
            result.atomically {
                $0[idx] = transformed
        return { $0! }

This code has a simple API and a simple implementation. Our thanks to Ashton for leading us towards the right path. 😊

Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts