Why doesn't array conform to Equatable, when its items are Equatable in Swift? Why doesn't array conform to Equatable, when its items are Equatable in Swift? arrays arrays

Why doesn't array conform to Equatable, when its items are Equatable in Swift?


Swift 4.1 update:

With the introduction of conditional conformance in Swift 4.1, Array now conforms to Equatable, so the issue should be resolved without the need to resort to any workarounds.

Also, Swift now allows a type to automatically synthesize Equatable conformance, provided all its members are Equatable, simply by declaring Equatable conformance as part of the original type definition (not an extension) but without implementing any of its requirements. This works for enums provided associated values, if any, are Equatable.

The code from this question can now be written much more concisely as below:

import Foundationstruct Post: Equatable {    let text: String}enum Result<T>: Equatable where T: Equatable {    case success(result: T)    case error}

This code will pass all the tests specified in the question:

func test() {    // Test 1: Check Post type for equality: OK    let post1 = Post(text: "post")    let post2 = Post(text: "post")    if post1 == post2 {        print("equal posts")    }    // Test 2: Check [Post] type for equality: OK    let arrayOfPosts1 = [post1, post2]    let arrayOfPosts2 = [post1, post2]    if arrayOfPosts1 == arrayOfPosts2 {        print("equal arrays of post")    }    // Test 3: Check Result<Post> type for equality: OK    let result1 = Result<Post>.success(result: post1)    let result2 = Result<Post>.success(result: post2)    if result1 == result2 {        print("equal results of post")    }    // Test 4: Check Result<[Post]> type for equality: OK    let arrayResult1: Result<[Post]> = Result<[Post]>.success(result: arrayOfPosts1)    let arrayResult2: Result<[Post]> = Result<[Post]>.success(result: arrayOfPosts2)    if arrayResult1 == arrayResult2 {        print("equal results of array of posts")    }}

Here is the output:

test()/* prints: equal posts equal arrays of post equal results of post equal results of array of posts*/


This issue totally sucks and still isn't fixed in Swift 4.

I worked around the issue by having a different type ArrayResult specifically for arrays of results, in addition to Result

public enum ArrayResult<T:Equatable> {    case success(result: [T])    case failure(error: Error)}extension ArrayResult: Equatable {    public static func ==(lhs: ArrayResult<T>, rhs: ArrayResult<T>) -> Bool {        switch (lhs) {        case .success(let lhsResult):            if case .success(let rhsResult) = rhs, lhsResult == rhsResult { return true }        case .failure(let lhsError):            // We cast associated Error to a NSError so we get Equatable behaviour            // (Apple guarantee that Error can always be bridged to an NSError)            if case .failure(let rhsError) = rhs, lhsError as NSError == rhsError as NSError { return true }        }        return false    }}func test() {    // Test 4: Check Result<[Post]> type for equality: NOW OK    let arrayResult1: ArrayResult<Post> = ArrayResult<Post>.success(result: arrayOfPosts1)    let arrayResult2: ArrayResult<Post> = ArrayResult<Post>.success(result: arrayOfPosts2)    if arrayResult1 == arrayResult2 {        print("equal results of array of posts")    }}


public func ==(lhs: Result<T>, rhs: Result<T>) -> Bool {    switch (lhs, rhs) {    case let (.success(lhsVal), .success(rhsVal)):        return lhsVal == rhsVal    case (.error, .error):        return true    default:        return false}

without extension