Weekly Swift articles, podcasts and tips by John Sundell.

Limiting collection mutations

Published on 05 Sep 2019

When designing APIs, we often want to limit the amount of mutations that any object can perform, since doing so tends to both make our code more robust — and can also make our APIs easier to understand.

One way to do that when working with collections is to keep the way we store values private, and instead only expose a more limited mutating API.

For example, this collection of Warning values can only be mutated by appending elements — it’s not possible for any external object to remove or mutate existing values:

public extension Warning {
    // By conforming to Sequence, our collection can be mapped, filtered,
    // and iterated over in many other ways - just like an array:
    struct Collection: Sequence {
        private var warnings = [Warning]()

        // We only want our API users to be able to append warnings
        // to this collection, so we only expose that method as
        // part of our public API:
        public mutating func append(_ warning: Warning) {
            warnings.append(warning)
        }

        // Here we reuse Array's iterator type, to avoid having to
        // create our own, and to keep all of Array's behaviors:
        public func makeIterator() -> Array<Warning>.Iterator {
            return warnings.makeIterator()
        }
    }
}