Daniel Tull: Blog

Tuple Comparison

Tuesday, 24 April 2018

Imagine we have a Version type with major, minor and patch integer values.

struct Version: Equatable {
  let major: Int
  let minor: Int
  let patch: Int
}

Here, Swift 4.1 automatically generates the == function required for the Equatable conformance, which is really really nice. However, we might also like to make it Comparable so that we could compare the app version to a given version we create in code.

Initially my implementation of this went something like the following:

extension Version: Comparable {

  static func < (lhs: Version, rhs: Version) -> Bool {

    if lhs.major < rhs.major {
      return true
    }

    if lhs.major > rhs.major {
      return false
    }

    if lhs.minor < rhs.minor {
      return true
    }

    if lhs.minor > rhs.minor {
      return false
    }

    return lhs.patch < rhs.patch
  }    
}

This gave me a base taste in my mouth because there’s a lot of comparisons that are happening that aren’t immediately obvious. Surely Swift has a better way?!

And of course it does. After attempting (and failing) to create an array of values to compare to each other, I tried putting each of the sub-version values into a tuple and comparing the tuples instead, which surprised me when it worked!

extension Version: Comparable {

  public static func < (lhs: Version, rhs: Version) -> Bool {

    let lhsTuple = (lhs.major, lhs.minor, lhs.patch)
    let rhsTuple = (rhs.major, rhs.minor, rhs.patch)

    return lhsTuple < rhsTuple
  } 
}

I hadn’t realised this was possible so I had to check to make sure I wasn’t abusing a side effect. It turns out tuple comparison was added in 2015 as a result of the Swift Evolution proposal SE-0015 by Kevin Ballard and is documented in the Swift Programming Language book:

You can compare two tuples if they have the same type and the same number of values. Tuples are compared from left to right, one value at a time, until the comparison finds two values that aren’t equal. Those two values are compared, and the result of that comparison determines the overall result of the tuple comparison. If all the elements are equal, then the tuples themselves are equal.