Skip to content

Instantly share code, notes, and snippets.

@an0
Last active August 29, 2015 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save an0/ebad817983b01663d869 to your computer and use it in GitHub Desktop.
Save an0/ebad817983b01663d869 to your computer and use it in GitHub Desktop.
Implicitly Unwrapped Optional is Really Dangerous and Its Type Matching is Buggy
/* 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