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)))
wheren
is anInt
(anInt
wrapped by 3 layers ofOptional
s)
Similarly, there are three kinds of values that an Int??
can have
.none
.some(.none)
.some(.some(n))
wheren
is 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