I posted this question on StackOverflow and it was suggested that it might be a good question to ask here:
We all know that you can use optional binding to unwrap an optional:
let b: String? = "bye"
if let greeting = b {
print(greeting) // "bye"
}
But if the value has multiple levels of optionals, only one will be removed:
let b: String?? = "bye"
if let greeting = b {
print(greeting) // "Optional(bye)"
}
Casting the value to the underlying type will remove the double optional:
let b: String?? = "bye"
if let greeting = b as? String {
print(greeting) // "bye"
}
I was surprised to find this works for any level of optionals:
let b: String??????? = "bye"
print(b as Any) // Optional(Optional(Optional(Optional(Optional(Optional(Optional("bye")))))))
if let greeting = b as? String {
print(greeting) // "bye"
}
Is there an explanation of why casting removes all levels of optionals? Is this a documented behavior?
Also:
let b: String??????? = "bye"
print(b as! String) // "bye"
but it gives the humorous warning:
Forced cast from 'String???????' only unwraps optionals; did you mean to use '!!!!!!!'.
1 Like
Type casting is part of the compiler, and I assume it is trivial to you that arg as! T returns T if it succeeds. In exactly the same way it happens for String???? -> String, since it is a particular case.
The warning you get will also be raised in a simple case like the following:
let str: String? = "foo"
print(str as! String)
The compiler is trying to tell you the forced cast has the same effect as a forced unwrap – str! (or b!!!!! in your case. I haven't counted the exclamation marks ).
Forced cast from 'String?' to 'String' only unwraps optionals, did you mean to use '!'?
print(str as! String) === print(str!)