Pretty much every way to assign optionals

Store a non-optional or an optional to an optional

The basics. This isn’t rocket science:

optItem = 5 // optItem is now .some(5)
optItem = optValue // optItem is whatever optValue is

Summary

How often do you do this? All the time

How ridiculous is this approach? Not at all

Store an optional to a non-optional

Many functions and methods that return optional values. When you use try? with throwing, that returns optional values too.  You often need to store those results to a non-optional variable or property.

To do this, you test for nil and then store an unwrapped version of any non-nil results. Here are a few approaches.

Conditional Binding

Use if let to conditionally bind the optional and then perform the assignment:

if let optItem = optItem { 
    item = optItem // if optItem is non-nil
}

You can also use if case if you really want to although these do exactly the same things as if let:

// Sugared optional
if case let optItem? = optItem { 
    item = optItem // if optItem is non-nil
}

// External let
if case let .some(optItem) = optItem {
    item = optItem // if optItem is non-nil
}

// Internal let
if case .some(let optItem) = optItem { 
    item = optItem // if optItem is non-nil 
}

Nil Coalescing

You can use nil coalescing to provide a fallback value:

item = optItem ?? fallbackValue

If you don’t want a fallback value, you can use the item’s original value:

item = optItem ?? item

A slight caution. I don’t know if the compiler optimizes away the “assign self to self” case. If it has to do both the check and assignment,  this may be less efficient than the if let approach.

Also, I’m not giving this high marks for efficiency or readability because I think it’s worth the extra if let words to make clear the intent that you only update item if optItem is non-nil

Summary

How often do you do this? Often

How ridiculous is this approach? Not at all

Update optional only if optItem is non-nil

This variation describes a scenario where you skip updates when an existing optional is nil. In this case, nil means “don’t touch this optional”. I can count up to zero the number of times this scenario has ever arisen for me.

The obvious solution:

if optItem != nil { optItem = newValue }

The extremely weird solution using a ? marker:

optItem? = nonOptionalValue

In this use of ?, the rhs must be a non-optional, guaranteed at compile time. This is a pretty obscure Swift language feature. (Thanks to Joe Groff for reminding me it existed.)

Or you could do this (which is kind of silly) for “test for non-nil receiver” assignment:

if let optValue = optValue {
    optItem? = optValue
}

In this example, the rhs of the ?-powered assignment has to be non-optional. Conditionally binding the optional enables you to use it with ?. Madalin Sava offers the following simple alternative. It gets high marks for parsimony, low marks (as everything in this section does) for non-obvious outcomes:

optItem? = optValue ?? optItem!

 

Summary

How often do you do this? Never

How ridiculous is this approach? Extremely

Update optional only if optItem is nil

This variation can best be described as “set once, use mostly”. Once assigned to a non-nil value, the optional should never be overwritten. The simplest approach is to check for nil before assignment:

if optItem == nil { optItem = newValue }

Or burn an operator, which you probably won’t want to do:

infix operator =?? : AssignmentPrecedence

// "fill the nil" operator
public func =??<T>(target: inout T?, newValue: T?) {
    if target == nil { target = newValue }
}
optItem =?? newValue

See also: SE-0024

Summary

How often do you do this? I don’t do this but I can see the utility when hooking up assets that you don’t want to overwrite. This is kind of a mad-world version of implicitly unwrapped optionals but one where you test to ensure you’ll never change them again, not one (as with IUO’s) where every successive change has to be a non-nil value.

How ridiculous is this approach? Not ridiculous but also not common.

Update optional only if new value is non-nil

This scenario basically mimics implicitly unwrapped optionals but with added safety and no IUO crashing. You always test for non-nil so once set to a valid value the optional will never return to nil.

Limit updates to non-nil new values and discard nil assignments:

if let newValue = newValue { optItem = newValue }

Or this (which feels wasteful as it performs a re-assignment for nil-values, doesn’t it?):

optItem = newValue ?? optItem

or burn an operator, which again you probably won’t want to do:

infix operator =? : AssignmentPrecedence

// "assign non-nil values" operator
public func =?<T>(target: inout T, newValue: T?) {
    if let newValue = newValue {
        target = unwrapped
    }
}

See also: Swift Evolution.

Summary

How often do you do this? I don’t but I can see how people might want to use this with non-IUO optionals.

How ridiculous is this approach? Not ridiculous but also not common.


I’m sure I’ve gotten some of this write-upwrong. Tell me and I’ll fix.

16 Comments

  • The thing I keep wanting is a sugared way to take a non-optional value and make it optional based on a bool condition. When combined with ?? it is really powerful…

    • Can you explain more about what that might look like? Because it’s easy enough to do let optional = bool ? nonoptional : nil

  • Also, instead of:

    if let optValue = optValue {
    optItem? = optValue
    }

    you can do:

    optItem? = optValue ?? optItem!

    Here force unwrapping is safe because it will only happen if optItem is not nil.
    I prefer reassigning a variable to if conditionals.

    • I’m hesitant to do that because what if both optValue and optItem are nil?

      • If optItem is nil, the rhs expression will not be evaluated, just like any optional chaining/assignment.

        • Argh. You’re right.

  • x.flatMap { y = $0 } where x is optional 😉

  • Looks to me like these two are equivalent, assuming sufficient optimization:

    if optItem == nil { optItem = newValue }
    optItem = optItem ?? optValue

    I was thinking about this while trying to figure out which operators makes the most sense in place of ‘=??’ and ‘=?’, and was considering ‘??=’ for the former because of the surface similarity to operators like ‘+=’:

    item += value // same as item = item + value
    optItem ??= optValue // same as optItem = optItem ?? optValue

    However, I don’t really think ‘??’ is a the same kind of operator as ‘+’ (and all of the others that can used like ‘+=’), so I don’t think ‘??=’ makes sense after all. Warming up to your choices ‘=??’ and ‘=?’ after all.

    • (copy & paste error, feel free to omit one ‘after all’ in my last paragraph)

  • That articles like this even need written confirms my notion that the lack of nil messaging in Swift was a bad decision. It’s the one thing that makes objective-c easy to deal with, as a human. I find debugging items with nils a lot easier than having to write this convoluted code always checking for nils or unwrapping objects.
    Thanks for taking the time to write this.

  • Hey Eric,

    Thanks for clearing all the doubts, although I am knowing all of them but still it clears the concept. Well, I saw that you came up if case let that really new for me. Can please clarify it more detail.

    what’s the difference between the below codes and when to use them appropriately?

    if case let optItem? = optItem {
    item = optItem // if optItem is non-nil
    }

    if let optItem = optItem {
    item = optItem // if optItem is non-nil
    }

    Thanks 🙂

  • Regarding the “Update optional only if new value is non-nil” case:

    Following the first example:

    if let newValue = newValue {
    optItem = newValue
    }

    I’d normally just shorten that, because both “optItem” and “newValue” are optionals and must be of the same type.
    The outcome is the same.

    optItem = newValue

    • Say optItem is “foo”. Then assign nil. Your solution, optItem is now nil. My solution, optItem remains “foo”.

  • I would love to see an Sugar for value of optional, if not nil. Otherwise default value.

    Here is a production example:


    static func createFbUser(fbId: String, name: String?) throws -> FbUser {
    let graph = "mutation createFBPerson($input: CreateFbUserInput!) {createFbUser(input: $input) {changedFbUser {fbID,name,id}}}"

    let variables_name = name != nil ? "\"\(name!)\"" : "null"
    let variables = "{ \"input\": { \"fbID\": \"\(fbId)\", \"name\": \(variables_name) } }"

    Here, I would be very glad to something like


    let variables = "{ \"input\": { \"fbID\": \"\(fbId)\", \"name\": \(name !? "null") } }"

    • Sorry, what I meant is


      let variables = "{ \"input\": {\"name\": \(name !? "\"\(name)\"": "null") } }"

      Which, if name has a value would produce “{ “input”: { “name”: “Maxim Veksler” } }”
      but if name does not have a value would produce “{ “input”: { “name”: null } }”