Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing optional arrays

Tags:

swift

Running the following code snippet in the playground gives an error:

let a: [Int]? = [1,2]
let b: [Int]? = [1,2]
a == b // value of optional type '[Int]?' not unwrapped; did you mean to use '!' or '?'?

While doing something similar for a 'simpler' optional type works:

var x: Int? = 10
var y: Int?
x == y // false

What is the reasoning behind the first case, of optional arrays, not being allowed? Why can't Swift first see if either side if nil (.None) and then if they are not, do the actual array comparison.

like image 624
Stefan Arentz Avatar asked Apr 06 '15 19:04

Stefan Arentz


1 Answers

The reason it works for simpler types is because there is a version of == that is defined for optionals that contain types that are Equatable:

func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool

But while Int is Equatable, Array is not (because it might contain something that is not equatable - in which case how could it be). All Equatable things have an == operator, but not all things with an == operator are Equatable.

You could write a special-case version of == specifically for optional arrays containing equatable types:

func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool {
    switch (lhs,rhs) {
    case (.Some(let lhs), .Some(let rhs)):
        return lhs == rhs
    case (.None, .None):
        return true
    default:
        return false
    }
}

You could also generalize this to cover any collection containing equatable elements:

func ==<C: CollectionType where C.Generator.Element: Equatable>
  (lhs: C?, rhs: C?) -> Bool {
    switch (lhs,rhs) {
    case (.Some(let lhs), .Some(let rhs)):
        return lhs == rhs
    case (.None, .None):
        return true
    default:
        return false
    }
}
like image 117
Airspeed Velocity Avatar answered Sep 28 '22 04:09

Airspeed Velocity