var opt1: Int??? = nil
var opt2: Int?? = nil
print(opt1 == opt2) // why is false?
At first I thought it was because of the different types(Int??? and Int??), so I custom a operator <==> and use the same code as the Optional' == source code to implement it:
extension Optional {
public static func <==> (lhs: Wrapped?, rhs: Wrapped?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l <==> r
case (nil, nil): //I think it should match here
return true
default:
return false
}
}
}
print(opt1 <==> opt2) // false
In other words, this is not caused by the type.
And Optional' ~= operator implementation in the source code:
public static func ~=(lhs: _OptionalNilComparisonType, rhs: Wrapped?) -> Bool {
switch rhs {
case .some:
return false
case .none:
return true
}
}
According to the code above,I think case (nil, nil): in static func <==> should match, so print(opt1 == opt2) and print(opt1 <==> opt2) should be true, but why it's false?
CodePudding user response:
There are four kinds of values that a Int??? can have:
.none(nil).some(.none)(a non nilInt???wrapping a nilInt??).some(.some(.none))(a non nilInt???wrapping a non nilInt??wrapping a nilInt?).some(.some(.some(n)))wherenis anInt(anIntwrapped by 3 layers ofOptionals)
Similarly, there are three kinds of values that an Int?? can have
.none.some(.none).some(.some(n))wherenis anInt
When you write nil, it always means .none of whatever type that context needs, so both opt1 and opt2 are .none here.
What happens when you pass them to the == operator? Well, After some overload resolution/type inference, the compiler finds that == takes a two Int??? parameters, but you have passed an Int?? as the second argument. Luckily, there exists a conversion from any value t of type T to type T? - .some(t).
So after being passed into the ==, opt2 changes from .none to .some(.none), as you can see from this code snippet:
func test(lhs: Int???, rhs: Int???) {
if case .none = lhs, case .some(.none) = rhs {
print("lhs is .none and rhs is .some(.none)")
}
}
test(lhs: opt1, rhs: opt2) // prints
Hence they are "not equal".
The debugger seems to be showing both .none and .some(.none) as "nil", possibly because both of their debugDescription/description is "nil".
If you don't care about the multiple layers of optionals, you can just unwrap them to a single layer by doing as? Int, then compare:
print((opt1 as? Int) == (opt2 as? Int)) // true

