Lucas Derraugh Lucas Derraugh - 3 months ago 14
Swift Question

Swift nil has a numeric value?

This is valid code in Swift:

println(nil < 1)


And the output will be true, likewise

println(nil > 1)


will be false (the number 1 is arbitrary, you can do the same for -1 and probably something else). The reason I ask is because I saw some code that tried to compare
"some_string".toInt()
to a numeric value and it compiled, which seems wrong considering
toInt()
returns
Int?
.

My question is, should this be valid syntax in Swift? If so, what is the numeric value of nil?

EDIT:

Looks like Swift Evolution tackled this issue by removing the optional comparison operators. This is no longer an issue in Swift 3.0 as it doesn't compile.

Answer

I believe what is happening is that the literal 1 is being implicitly typecast to the Int? type by the comparison to nil. For those who aren't used to Swift, I'll explain a little further. Swift has a concept called "optionals", which can either have a value or be nil. (For anyone familiar with Haskell, this is basically the Maybe monad.) It's illegal to assign nil to a variable that wasn't explicitly defined as optional, so let i: Int = nil will be rejected by the compiler. This allows for several benefits which are out of the scope of this answer, and it's a rather clever way to do it.

What's happening here, though, is that the literal 1 is a valid value of several types: Int, Int32, Int64, UInt32, UInt64, etc., etc., etc. And it's also a valid value of the optional versions of those types: Int?, Int32?, etc.

So when the Swift compiler sees a comparison between a literal value and nil, it tries to find a type that both these values would be valid for. 1 is a valid value of the Int? type, and nil is also a valid value of the Int? type, so it applies the comparison operator with the type signature (Int?, Int?) -> Bool. (That's the comparison operator that takes two Int? values and returns a Bool). That operator's rules say that nil values sort lower than anything else, even Int.min, and so you get the result seen in the OP's question.