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?
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