According to SE-0054 , ImplicitlyUnwrappedOptional<T> no longer a separate type; now there is only Optional<T> .
Ads can still be annotated as implicitly deployed optional T! but it just adds a hidden attribute informing the compiler that their value can be forcibly expanded in contexts that require their expanded type T ; their actual type is now T? ,
So you can think of this declaration:
var str: String!
what it actually looks like:
@_implicitlyUnwrapped // this attribute name is fictitious var str: String?
Only the compiler sees this @_implicitlyUnwrapped attribute, but it allows you to implicitly expand the str value in contexts that require String (its type is unwrapped):
// 'str' cannot be type-checked as a strong optional, so the compiler will // implicitly force unwrap it (causing a crash in this case) let x: String = str // We're accessing a member on the unwrapped type of 'str', so it'll also be // implicitly force unwrapped here print(str.count)
But in all other cases, when str can be type checked as a strong option, it will be:
// 'x' is inferred to be a 'String?' (because we really are assigning a 'String?') let x = str let y: Any = str // 'str' is implicitly coerced from 'String?' to 'Any' print(str) // Same as the previous example, as 'print' takes an 'Any' parameter.
And the compiler always prefers to consider it as such compared to forced deployment.
As the sentence says (my emphasis):
If the expression can be explicitly checked with a type with a strong optional type, it will . However, type checking will revert to forced optional if necessary. The effect of this behavior is that the result of any expression that refers to a value declared as T! will have type T or type T? ,
When it comes to string interpolation, the compiler uses this initializer from the _ExpressibleByStringInterpolation protocol to evaluate the string interpolation segment:
/// Creates an instance containing the appropriate representation for the /// given value. /// /// Do not call this initializer directly. It is used by the compiler for /// each string interpolation segment when you use string interpolation. For /// example: /// /// let s = "\(5) x \(2) = \(5 * 2)" /// print(s) /// // Prints "5 x 2 = 10" /// /// This initializer is called five times when processing the string literal /// in the example above; once each for the following: the integer '5', the /// string '" x "', the integer '2', the string '" = "', and the result of /// the expression '5 * 2'. /// /// - Parameter expr: The expression to represent. init<T>(stringInterpolationSegment expr: T)
Therefore, when implicitly called by your code:
var str: String! str = "Hello" print("The following should not be printed as an optional: \(str)")
How str actual type is String? by default, this is what the compiler will infer from the common placeholder T Therefore, the str value will not be forcibly expanded, and you will eventually see a description for optional.
If you want the IUO to be force deployed when used in string interpolation, you can simply use the force deployment operator ! :
var str: String! str = "Hello" print("The following should not be printed as an optional: \(str!)")
or you can cast it to an optional type (in this case String ) to force the compiler to force it to be expanded for you:
print("The following should not be printed as an optional: \(str as String)")
both of which, of course, will crash if str is nil .