Should redundant comparison to `Optional.none` emit a warning?

When comparing a non-optional type to nil, the compiler emits a warning:

let value = "non-optional"

// warning: comparing non-optional value of type 'String' to 'nil' always returns false 
if value == nil {
  print("value is nil")
}

Interestingly, when performing an equivalent check using Optional.none instead of nil, the compiler doesn't emit a warning:

let value = "non-optional"

if value == .none {
  print("nil")
}

Is this a bug / oversight? Since these two checks are functionally equivalent I would expect them to both emit a warning.

I see this warning is implemented here. If this seems like a bug / oversight, could this be updated to warn on redundant == .none comparisons (like it does for == nil) without running an evolution proposal?

1 Like

This is likely one of the various differences in handling .none and nil across the language, especially in automatic promotion as you've seen. I think they're considered bugs but I'll let one of the language developers speak to that.

There are also some other areas where .none and nil aren’t treated the same, for example failable inits:

class C1 {
    init?() {
        return .none // error: 'nil' is the only return value permitted in an initializer
    }
}

class C2 {
    init?() {
        return nil // ok
    }
}

This seems like a valid difference. The compiler has no way to be certain you mean Optional.none in C1.init.

How so? The only valid return from a failable init is an Optional, no?

4 Likes

I put together an implementation for this change: Add warning when comparing a non-optional value to `Optional.none` by calda · Pull Request #60893 · apple/swift · GitHub

3 Likes

I think it's the automatic promotion of types inside of a critical object lifecycle section of code that the language rules forbid it for crystal-clear intentions and understanding

I think, theoretically, that value == .none should emit an error because String has no member named none.
I understand that that will be a breaking change, though.

2 Likes

Is that even a real return statement? I mean you can't return a C2, so I'd say that when you write return nil it doesn't mean anything like return Optional<C2>.none, it simply means failed to init, but instead of inventing a new syntax for that they use return nil.

1 Like

By the same logic "return .none" from an init couldn't possibly mean anything other than "return nil" (and IMHO should be allowed).

If we removed "nil" from the language altogether (not I'm saying we should, just that we could) and use ".none" in all places we currently use nil - swift would not be any less swifty.

1 Like