7
votes

Swift tuples are not Equatable, and as compound types, they can't be made Equatable through protocol extension. The workaround (as documented in another answer) is to create an overload for the == operator for each arity of tuples.

Interestingly, one can declare the == operator for regular tuples and use it to compare tuples with named fields:

func ==<T1: Equatable, T2: Equatable>(lhs: (T1,T2), rhs: (T1,T2)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1
}

var one = ("One", 1)
let two = ("Two", 2)
print(one == two) // "false"

typealias NamedTuple2 = (name: String, value: Int)
var namedone: NamedTuple2 = (name: "One", value: 1)
let namedtwo: NamedTuple2 = (name: "Two", value: 2)
print(namedone == namedtwo) // "false"
print(namedone == one) // "true"

Arrays of tuples also need a custom overload to be compared as a whole:

func ==<T0: Equatable, T1: Equatable>(lhs: [(T0, T1)], rhs: [(T0, T1)]) -> Bool {
    if lhs.count != rhs.count {
        return false
    }
    for (index, value) in lhs.enumerate() {
        if !(value == rhs[index]) {
            return false
        }
    }
    return true
}

let array12: [(String, Int)] = [one, two]
let array3: [Tuple2] = [("Three", 3)]
print(array12 == array3) // "false"

However, this operator doesn't accept an array of named tuples:

let namedarray12: [NamedTuple2] = [namedone, namedtwo]
let namedarray3: [NamedTuple2] = [array3[0]]
print(namedarray12 == namedarray3)
// error: binary operator '==' cannot be applied to two '[NamedTuple2]' operands

Is there a way to test equality of arrays of named tuple, without declaring an overload of == for the particular named tuple?

1

1 Answers

12
votes

The method SequenceType.elementsEqual(_,isEquivalent:) accepts a predicate for comparing elements. The same == overload works for both named and unnamed tuples. So instead of trying to apply == to the arrays as a whole, use elementsEqual.

func ==<T1: Equatable, T2: Equatable>(lhs: (T1,T2), rhs: (T1,T2)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1
}

let namedarray: [(name: String, value: Int)] = [(name: "One", value: 1), (name: "Two", value: 2)]
// namedarray == namedarray12
namedarray.elementsEqual(namedarray12, isEquivalent: ==) // true