swiftlanguage-lawyerundefined-behaviorswift-optionals

Can I safely assign a non-nil value to a non-optional nil object in Swift?


If you bridge C or Objective-C to Swift, you can misuse _Nonnull to falsely make a guarantee to Swift that a value never holds nil.

However, suppose I have this situation in Swift:

var nonoptional: NSObject = questionable_objc_function() // Returns nil
nonoptional = NSObject()

Does this cause immediate undefined behavior, or is this safe as long as I am sure to assign a real non-nil value to nonoptional before reading or using the value of nonoptional? Is this safe, or might there be speculative preloading or other things under the hood, causing this to be undefined behavior anyway?

Where this might be used is if I bridge a C global to Swift that gets immediately initialized to a valid value in main.swift before anything else.


Solution

  • This line not crashing:

    var nonoptional: NSObject = questionable_objc_function() // Returns nil
    

    was reported as reported as the issue SR-6822. The response was

    The cost of checking every nonnull return value was determined to be too high, but maybe we could do it in Debug builds.

    But this has not been implemented as of Swift 6.2. I would say that this is safe for now. This could certainly change in the future.

    Note that this only applies to Objective-C classes that are not bridged to Swift value types. If questionable_objc_function returns an nonnull NSUUID *, this will be automatically bridged to UUID in Swift, and the program will crash during the bridging process.

    if I bridge a C global to Swift that gets immediately initialized to a valid value in main.swift before anything else.

    This is a slightly different situation from questionable_objc_function. There is technically no need to check whether the current value of a C global is null when you are setting it (there indeed is no such check in Swift 6.2), but I can't find any explicit guarantees either. If C does guarantee that this works (I'm not a C expert), you should probably write a C wrapper for setting the value.