serz serz - 1 month ago 4x
Swift Question

Are _Nullable and _Nonnull useful for anything other than Swift interop?

Does the Objective-C compiler actually warn you if it thinks that you may be passing

to a parameter marked with

Or is it merely a hint to whatever tool converts between Swift and Objective-C to better deal with Swift optionals?


On its own, there is warning only in the extremely trivial case: when you pass nil to a function accepting _Nonnull value.

NSObject* _Nonnull test(NSObject* _Nonnull) {
    test(nil);  // warning

    NSObject* _Nullable f = nil;
    test(f); // no warning (passing _Nullable to _Nonnull), only warn in static analysis

    NSObject* _Nonnull g = [[NSObject alloc] init];
    g = nil; // no warning (!) (assigning nil to _Nonnull)

    if (g != nil) {  // no warning (unnecessary '!= nil' comparison)

    return nil; // no warning (returning nil to _Nonnull)

The code above when compiled in Xcode 7

(There is a -Wnullable-to-nonnull-conversion flag but it doesn't seem to have any effect to the code above.)

As documented, the three attributes will not change the behavior of the code:

… Note that, unlike the declaration attribute nonnull, the presence of _Nonnull does not imply that passing null is undefined behavior: fetch is free to consider null undefined behavior or (perhaps for backward-compatibility reasons) defensively handle null.

Beyond the compiler, it will also help the static analyzer, but again clang's static analyzer will only catch the trivial case where it knows for sure you are assigning a nil to a _Nonnull (i.e. the test(f) example above).

Nevertheless, it is still useful to mark a pointer _Nonnull/_Nullable as

  1. Documentation;
  2. Allow Swift developers to use your library better;
  3. The compiler will emit warnings everywhere if you don't add those annotations