Why is Equatable not defined for optional arrays
Can someone give me a good reason for why this doesn't work:
let a: [Int]? = [1]
let b: [Int]? = nil
a == b
This would be my proposed (if inelegant) solution. But it's trivial, so I feel like I'm missing a good reason why this isn't implemented.
func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool {
if let lhs = lhs, let rhs = rhs {
return lhs == rhs
}
else if let _ = lhs {
return false
}
else if let _ = rhs {
return false
}
return true
}
Update: Conditional conformance has been implemented in Swift 4.1. Arrays and optionals of Equatable
elements are themselves
Equatable
now, and your code
let a: [Int]? = [1]
let b: [Int]? = nil
a == b
compiles and works as expected in Xcode 9.3. The workarounds are not needed anymore.
(Old answer:) Optionals can be compared only if the underlying wrapped type is equatable:
public func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool
Now Arrays can be compared if the element type is equatable:
/// Returns true if these arrays contain the same elements.
public func ==<Element : Equatable>(lhs: [Element], rhs: [Element]) -> Bool
but even for equatable types T
, Array<T>
does not conform to the Equatable
protocol.
At present, this is not possible in Swift, see for example Why can't I make Array conform to Equatable? for a discussion in the Apple developer forum. This change with the implementation of SE-0143 Conditional conformances in Swift 4.
Your implementation looks correct, here is a possible different one using switch/case with pattern matching:
func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?) : // shortcut for (.Some(l), .Some(r))
return l == r
case (.None, .None):
return true
default:
return false
}
}