Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift error comparing two arrays of optionals

Tags:

swift

I get a compilation error in the next Swift code

var x:Array<Int?> = [1,2]
var y:Array<Int?> = [1,2]
if x == y {  // Error
}

If both arrays are Array<Int> it works fine, but if at least one of them is optional it throws an error like the next:

Binary operator '==' cannot be applied to two Array<Int?> operands

I filed a bug report months ago but I had no answer. It still occurs in Swift 1.2.

Why is this happening?

like image 932
sangonz Avatar asked Feb 10 '23 18:02

sangonz


1 Answers

The issue here is the distinction between something having an == operator, versus something being “equatable”.

Both Optional and Array have an == operator, that works when what they contain is equatable:

// if T is equatable, you can compare each entry for equality
func ==<T : Equatable>(lhs: [T], rhs: [T]) -> Bool
// if T is equatable, you can compare the contents, if any, for equality
func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool

let i: Int? = 1
let j: Int = 1
i == j          // fine, Int is Equatable
["a","b"] == ["a","b"]  // and so is String

But they themselves do not conform to Equatable. This makes sense given you can put a non-equatable type inside them. But the upshot of this is, if an array contains a non-equatable type, then == won’t work. And since optionals aren’t Equatable, this is the case when you put an optional in an array.

You'd get the same thing if you tried to compare an array of arrays:

let a = [[1,2]]
let b = [[1,2]]
a == b  // error: `==` can’t be applied to `[Array<Int>]`

If you wanted to special case it, you could write == for arrays of optionals as:

func ==<T: Equatable>(lhs: [T?], rhs: [T?]) -> Bool {
    if lhs.count != rhs.count { return false }
    for (l,r) in zip(lhs,rhs) {
        if l != r { return false }
    }
    return true
}

For a counter-example, since Set requires its contents to be hashable (and thus equatable), it can be equatable:

let setarray: [Set<Int>] = [[1,2,3],[4,5,6]]
setarray == [[1,2,3],[4,5,6]]  // true
like image 144
Airspeed Velocity Avatar answered Feb 13 '23 21:02

Airspeed Velocity