Search code examples
swift2optional-variables

Swift 2: is there a short syntax to conditionally set a non-optional variable from an optional variable?


Sometimes I find myself writing swift 2 code like this:

class Test {
    var optionalInt: Int?
    var nonOptionalInt: Int = 0
    func test() {
        if let i = optionalInt {
            nonOptionalInt = i
        }
        // do more stuff
    }
}

where the problematic part is this:

if let i = optionalInt {
    nonOptionalInt = i
}

In words: if optionalInt has a value, assign it to the variable nonOptionalInt, else do nothing.

Is there an equivalent way in swift 2 to express this in a elegant single line without adding an intermediate variable with if let i?

Edit

after contemplating the first answers...

Obviously there is an equivalent way

if optionalInt != nil {
    nonOptionalInt = optionalInt!
}

Ternary operators ? : are not equivalent as they may trigger a didSet which the original code does not (good if this is a intended side effect)

The most elegant answer so far appears to be

nonOptionalInt = optionalInt ?? nonOptionalInt

it may also trigger a didSet like the ternary operator and therefore is not equivalent (also good if this is intended).

I think my wish to Apple would be something like

nonOptionalInt = optionalInt ?? 

or

nonOptionalInt ??= optionalInt

Solution

  • What you are looking for is the nil coalescing operator.

    You would use it like so in this case:

    nonOptionalInt = optionalInt ?? nonOptionalInt
    

    EDIT

    re: your last edit to your question:

    "I think my wish to Apple would be something like nonOptionalInt ??= optionalInt"

    ...why wish when you can build it? :)

    I haven't thought about it enough to decide whether I would recommend something like this for the general case, but if it helps in your situation you can create a ??= operator that does what you ask like this:

    infix operator ??= {}
    
    func ??= <T>(inout lhs: T, rhs: T?) -> Void {
      guard let value = rhs else { return }
      lhs = value
    }
    

    then, to see it in action:

    let optionalNil: String? = nil,
      optionalValue: String? = "optionalValue",
      implicitlyUnwrappedNil: String! = nil,
      implicitlyUnwrappedValue: String! = "implicitlyUnwrappedValue"
    var a = "a", b = "b", c = "c", d = "d"
    
    a ??= optionalNil               // "a"
    b ??= optionalValue             // "optionalValue"
    c ??= implicitlyUnwrappedNil    // "c"
    d ??= implicitlyUnwrappedValue  // "implicitlyUnwrappedValue"
    

    (note that you would add this definition at top-level scope, outside of the definition of any class, struct, or other type)