Blog

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 result.value.map { $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