[swift-evolution] Proposal Sketch: simplify optional unwrapping syntax

ilya ilya.nikokoshev at gmail.com
Fri Dec 11 10:58:09 CST 2015


This was discussed in the old forums... ah, those times :)

As before, I don't think this idea is workable, because this only works for
names that describe local variables and only if they are not captured by
long-running closures.

Imagine the code

class C {
  var layer: CALayer? { can be changed from other threads }

  func f() {
    var nearestX = X()

    doSomethingAsync {
        nearestX = compute(...)
    }

    // later

    if nearestX != nil {
      // *can't* use nearestX without unwrapping
    }

    guard layer != nil else { continue }
    // *can't* use layer without force unwrapping
  }
}

This will, however, work if we do create a new name that shadows an old
name with if let nearestX = nearestX or guard let layer = layer.
let here plays an important role by reminding that original nearestX or
layer may have already changed in the meantime.

I agree this shadowing may not look best if nearestX and layer *are* plain
old local variables. In that case those names are under your control and I
would find this refactoring benefitial:

    let maybe_nearestX = ...
    let maybe_layer = ...

    if let nearestX = maybe_nearestX {
      // use nearestX
    }

    guard let layer = maybe_layer else { continue }
    // use layer


On Fri, Dec 11, 2015 at 7:11 PM, Daniel Hooper via swift-evolution <
swift-evolution at swift.org> wrote:

> A very common pattern in swift code is to "guard let" or "if
> let" optionals  - this works by creating a new non-optional variable to be
> used by future code. Often, the new variable is given the same name as the
> original optional variable, creating a shadow variable. This approach leads
> to odd looking code like this:
>
> if let nearestX = nearestX { closest = nearestX }
> guard let layer = layer else { continue }
> // use layer
>
> At a glance, and to Swift newcomers, this code looks completely
> non-sensical. It's also verbose for simply ensuring the variable is
> non-nil.
>
> The solution:
> Swift should generate unwrapped shadow variables after nil checking. The
> compiler would treat the below code as if it had created an unwrapped
> shadow variable.
>
> if nearestX != nil { closest = nearestX } // notice that nearestX isn't
> force unwrapped
> guard layer != nil else { continue }
> // use layer, without force unwrapping
>
> Why force unwrapping isn't a good alternative:
> You might suggest force unwrapping variables when they're inside an if or
> after a guard that checks for nil. While this does allow for the "layer =
> nil" syntax, it results in code that is less resilient to change. Imagine
> that this code was written:
>
> {code:java}
> if layer != nil {
> // lots of code before //
> layer!.backgroundColor = newColor
> // lots of code after //
> }
> {code}
>
> And much later, you need to use some of the the code in the if body
> elsewhere, so you copy and paste a huge chunk of it. You likely won't
> notice the force unwrap, and unless you're lucky, you probably didn't paste
> it into an if that checked layer for nil. So you get a crash. Because of
> this, it's important we make safe optional unwrapping as easy and sensical
> as possible, and minimize the situations that you would need to force
> unwrap.
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151211/1ac0c0d1/attachment.html>


More information about the swift-evolution mailing list