11

Why does the last statement fail to compile with the error: Binary operator '==' cannot be applied to two '[[Simple]]’ operands, and is there a way way to modify the Simple struct or extend the == operator to be able to perform equality checks on nested arrays (or dictionaries)?

var i1: [Int] = [1]
var i2: [Int] = [1]
i1 == i2 // -> true


var i3: [[Int]] = [[1], [2]]
var i4: [[Int]] = [[1], [2]]
i3 == i4 // -> true


struct Simple: Equatable, Hashable {
    let message: String

    var hashValue: Int {
        return message.hashValue
    }
}
func ==(lhs: Simple, rhs: Simple) -> Bool {
    return lhs.message == rhs.message
}

var a: [Simple] = [Simple(message: "a")]
var b: [Simple] = [Simple(message: "a")]
a == b // -> true

var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
x == y // -> ERROR! Binary operator '==' cannot be applied to two '[[Simple]]’ operands
1
  • Your problem has been solved in Swift 4.1. Commented Apr 27, 2018 at 17:49

2 Answers 2

15

Update: Conditional conformance has been implemented in Swift 4.1. In particular:

The standard library types Optional, Array, and Dictionary now conform to the Equatable protocol when their element types conform to Equatable. ...

(from the Swift CHANGELOG).

Arbitrarily nested arrays of Equatable elements are Equatable now and can be compared with ==. Your code

var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
x == y

compiles in Xcode 9.3 if Simple is Equatable.


(Old answer:) The reason is similar as in Why is Equatable not defined for optional arrays. Arrays can be compared with == if the element type is Equatable:

/// Returns true if these arrays contain the same elements.
public func ==<Element : Equatable>(lhs: [Element], rhs: [Element]) -> Bool

That's why

var a: [Simple] = [Simple(message: "a")]
var b: [Simple] = [Simple(message: "a")]
a == b // -> true

compiles.

But even for equatable types T, Array<T> does not conform to the Equatable protocol, compare Why can't I make Array conform to Equatable?. Therefore, in

var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
x == y // -> ERROR! Binary operator '==' cannot be applied to two '[[Simple]]’ operands

x and y are arrays with the element type [Simple] which does not conform to the Equatable protocol, and there is no matching == operator.

You could define a generic == operator for simply nested arrays as

func ==<Element : Equatable> (lhs: [[Element]], rhs: [[Element]]) -> Bool {
    return lhs.count == rhs.count && !zip(lhs, rhs).contains {$0 != $1 }
}

or more simply (as suggested by @kennytm):

func ==<Element : Equatable> (lhs: [[Element]], rhs: [[Element]]) -> Bool {
    return lhs.elementsEqual(rhs, by: ==)
}

This makes x == y compile and work as expected. At present, there seems to be no way to define a == operator on arbitrarily nested arrays.

Sign up to request clarification or add additional context in comments.

3 Comments

Perhaps update the implementation to lhs.elementsEqual(rhs, by: ==)?
Suggestion: since github.com/apple/swift-evolution/blob/master/proposals/… was not included in Swift 4, update the answer
@PetroKorienev: Done! – SE-0143 has not been implemented yet, but the special case for arrays of equatable elements has, and that is actually sufficient for this problem.
1

You can do it by implementing a == function for it, like following:

func == (lhs: [[Simple]], rhs: [[Simple]]) -> Bool {
    //your code
}

4 Comments

Sorry for the down vote, but this question is way more complicated than what your answer implies.
@Jeff You are entitled to your opinion but I always prefer simple solutions over complicated ones. YAGNI applies here.
My comment was not about preferring an unnecessarily complex answer. Your answer is not a solution to this question. Your answer is incomplete. The question is more complex than you seem to comprehend.
My answer is a solution and is complete. It is the simplest way of solving the problem that was described. You seem to make things more complicated than they really are.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.