Last active
August 29, 2015 14:26
-
-
Save an0/ebad817983b01663d869 to your computer and use it in GitHub Desktop.
Implicitly Unwrapped Optional is Really Dangerous and Its Type Matching is Buggy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Implicitly unwrapped optional is really dangerous, especially when unwrapped unexpected. | |
For example, I expect here `a` will be checked again `nil` first before being unwrapped and compared to `b`. | |
That is to say, I thought there are `==(lhs: T?, rhs: T)` and `==(lhs: T, rhs: T?)`. But there aren't. | |
There are only `==(lhs: T, rhs: T)` and `==(lhs: T?, rhs: T?)`. | |
Reasonably, (lhs: T!, rhs: T) matches better the former than latter so the former is picked so crash. */ | |
let a: Int! = nil | |
let b: Int = 1 | |
a == b | |
/* However, even if I supply `==(lhs: T?, rhs: T)` and `==(lhs: T, rhs: T?)` myself, | |
(lhs: T!, rhs: T) and (lhs: T, rhs: T!) pick `==(lhs: T, rhs: T)` instead, which quite bewilders me. */ | |
public func ==<T : Equatable>(lhs: T?, rhs: T) -> Bool { | |
if lhs == nil { | |
return false | |
} else { | |
return lhs! == rhs | |
} | |
} | |
public func ==<T : Equatable>(lhs: T, rhs: T?) -> Bool { | |
if rhs == nil { | |
return false | |
} else { | |
return lhs == rhs! | |
} | |
} | |
/* To prove that it is not because type-specific version(`==(lhs: Int, rhs: Int)`) matchs better than generic version, | |
I also supply type-specific versions. */ | |
public func ==(lhs: Int?, rhs: Int) -> Bool { | |
if lhs == nil { | |
return false | |
} else { | |
return lhs! == rhs | |
} | |
} | |
public func ==(lhs: Int, rhs: Int?) -> Bool { | |
if rhs == nil { | |
return false | |
} else { | |
return lhs == rhs! | |
} | |
} | |
/* I believe it is a type-matching bug because the call of `foo(a:Int!, Int)` below correctly picks `foo(a: Int?, b: Int)`. */ | |
func foo(a: Int, b: Int) { | |
print("Int Int") | |
} | |
func foo(a: Int?, b: Int) { | |
print("Int? Int") | |
} | |
func foo(a: Int, b: Int?) { | |
print("Int Int?") | |
} | |
func foo(a: Int?, b: Int?) { | |
print("Int? Int?") | |
} | |
foo(a, b: b) | |
/* If it is confirmed to be a bug and gets fixed later I think Swift Standard Library should supply safe-net versions of | |
overloads like what I supplied above so there will be less unexpected unwrappings of implicitly unwrapped optionals. */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment