2

I can't understand how string interpolation works in Swift 3. Here are two variables, optional x and implicitly unwrapped optional y:

let x: Int? = 1
let y: Int! = 2

Printing of this two optionals looks quite logic:

print(x) // Optional(1)
print(y) // 2

But why string interpolation works in other way?

print("x: \(x)") // x: Optional(1)
print("y: \(y)") // y: Optional(2)

Why should I unwrap already unwrapped optional?

print("y: \(y!)") // y: 2

Let's assume here was used CustomStringConvertible protocol that uses description property to convert Int! to String. But why here's no y: Optional(2)?

print("y: \(y!.description)") // y: 2
print("y: \(y?.description)") // y: Optional("2")
print("y: \(y.description)")  // y: 2

Could anyone please explain that?

Leo
  • 3,003
  • 5
  • 38
  • 61

1 Answers1

1

print, as part of its own internal workings, unwraps Optionals (the regular, unwrap-yourself kind). String interpolation doesn't do this for you, it just converts whatever you give it.

Here's an explanation of the last example:

  • print("y: \(y!.description)") // y: 2

    y has a type Int!, which is explicitly unwrapped, to give its Int content. description is called on it. description returns a String. If y was nil, this would crash.

  • print("y: \(y?.description)") // y: Optional("2")

    Optional chaining is used to call description on y, only if it's non-nil. If it's nil, then description isn't called in the first place, and the nil is propagated. The result of this expression is a String?.

  • print("y: \(y.description)") // y: 2

    Like case 1, y starts as an Int!, but is this time implicitly unwrapped, to give its Int content. description is called on it. description returns a String. If y was nil, this would crash.

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • 1
    Thanks for answer, nice point about `String?` in second case. However, it doesn't explain why `print("y: \(y)")` gives `y: Optional(2)`. Edit: duplicate tag – Leo Nov 30 '16 at 20:02
  • 1
    It's a shortfall of the type system, as covered in the other question this is linked to. Hopefully it gets fixed, but I won't be losing sleep over it. Just don't use implicitly unwrapped optionals. Apart from IBOutlets and recursive closures, there's almost never a good reason for them. – Alexander Nov 30 '16 at 20:04
  • There are some reasons, mostly because of Obj-C and Swift interactions. For me it was "A Constant That Cannot Be Defined During Initialization". But that SE-0054 is truly transforms "Implicitly Unwrapped Optionals" to "Schrödinger Optionals". – Leo Nov 30 '16 at 20:15
  • I would design around avoiding that sort of two stage initialization. If you give me a concrete case I can help you out – Alexander Nov 30 '16 at 20:19