Fat GrinCatchlines, Articles, About

Removing post/pre increment in my Swift project

17 May 2016

With the recent deprecation and future removal of the post and pre increment and decrement operators in Swift, I recently updated the code in Catchlines, my Swift project, ready for these changes. Most of the work was very simple and involved swapping n++ with n += 1 or similar. I only had one case where I was actually relying on the post increment behaviour.

I had some code similar to the following from early on in the project. I had a type Bar in this case, and a type for managing a collection of Bar instances, Foo.

struct Bar {}

struct Foo {
    let data: [Bar]
}

I had wanted to treat Foo as a sequence so I'd added the following code (I was a bit greener with Swift when I wrote this, but I'm including it to demonstrate the only real use case of post increment I had).

extension Foo: SequenceType {
    struct BarGenerator: GeneratorType {
        var data: [Bar]
        var idx: Int = 0
        init(data d: [Bar]) {
            data = d
        }
        mutating func next() -> Bar? {
            if idx < data.count {
                return data[idx++]
            }
            return nil
        }
    }
    func generate() -> BarGenerator {
        return BarGenerator(data: data)
    }
}

Here I wrote a small indexing GeneratorType for Foo that took a copy of the data and kept track of an index for how far through the sequence we were. When checking what to return next I made sure I wasn't out of bounds, and then returned the item in my stored data at the current index, and post incremented the index immediately after using it.

I can re-write that next method to guard against the out of bounds error and return nil. I can then use a temporary variable to store the index I want to return and increment idx.

mutating func next() -> Bar? {
    guard idx < data.count else {
        return nil
    }
    let val = idx
    idx += 1
    return data[val]
}

This doesn't seem as elegant, but probably reads much better to someone who isn't aware of what post and pre increment do.

What I really needed to do

I now know that I really shouldn't even have a BarGenerator, I should just be using the IndexingGenerator provided by Array, but you live and learn.

extension Foo: SequenceType {
    func generate() -> IndexingGenerator<[Bar]> {
        return data.generate()
    }
}

— Ryan Gibson —