Blog

Swift Tip: Local Computed Variables

Sometimes we want to compute the same expression twice in a function. For example, here’s a simplified version of some XML parsing code we recently wrote:

func parseElement(name: String, text: String) {
    if name == "trk" {
        let t = text.trimmingCharacters(in: .whitespaces)
        // process element
    } else if name == "ele" {
        let elevationText = text.trimmingCharacters(in: .whitespaces)
        guard let elevation = Int(elevationText) else { return }
    } else {
        // no need to trim text
    }
}

Note that we’ve duplicated the text.trimmingCharacters(in: .whitespaces) in two branches. Of course, we can easily pull it out into a variable outside of the if statement:

func parseElement(name: String, text: String) {
    let trimmed = text.trimmingCharacters(in: .whitespaces)
    if name == "trk" {
        let t = trimmed
        // process element
    } else if name == "ele" {
        guard let elevation = Int(trimmed) else { return }
    } else {
        // no need to trim text
    }
}

This works fine, except that it can really slow down our parsing code: we’re trimming the text for every element that we parse, but we only really need it in case of trk and ele elements. If trimmed were a struct or class property, we could write lazy in front of it, but alas, that doesn’t work for a local variable.

Instead, we can make trimmed a local computed property, like so:

func parseElement(name: String, text: String) {
    var trimmed: String { text.trimmingCharacters(in: .whitespaces) }
    if name == "trk" {
        let t = trimmed
        // process element
    } else if name == "ele" {
        guard let elevation = Int(trimmed) else { return }
    } else {
        // no need to trim text
    }
}

This will compute trimmed only when you need it. Of course, this solution has its drawbacks, too: if you access the trimmed computed property more than once, it also computes the value more than once. You have to be careful to only use it when you need it, and if you do need it multiple times, cache the value.

The technique above can also work well for complicated loop conditions. For example, here’s a completely made-up while loop with three conditions:

while !done && queue.count > 1 && queue[1] != "stop" {
    // process the queue
}

If we want to group the two queue-related conditions into one, a local computed property can be used:

var canContinue: Bool { return queue.count > 1 && queue[1] != "stop" }
while !done && canContinue {
    // process the queue
}

For more advanced tricks with local properties, watch Swift Talk 61 and Swift Talk 63, where we use Swift 4’s KeyPaths to build a new hybrid type, combining useful features of both classes and structs — a fun way to push the limits of the language!

Thanks to our Subscribers, both these episodes are public. 🙇‍♂️

If you’d like to support us, you can subscribe too.

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

Back to the Blog

recent posts