Swift, in contrast with Objective-C, makes a distinction between values that may be nil
and values that can never be nil
through its use of Optionals. Due to the fact that Objective-C does not make this distinction, Objective-C functions that do not use the Nullability annotations are imported with parameters of the implicitly unwrapped optional type. Unfortunately, this allows users to write their own Swift code that looks like this:
func foo(bar: Int!) {
//…
}
Due to the confusion this may cause, we would like to propose the removal of implicitly unwrapped optionals in function signatures, both as parameters and as return values. Discussion on this topic may be found here.
Implicitly unwrapped optionals are currently allowed in function declarations. Consider the following function:
func triple(forceUnwrapping aNumber: Int) -> Int {
return aNumber * 3
}
let possiblyNil = Int("foo")
triple(forceUnwrapping: possiblyNil)
possiblyNil
is an Int?
; thus, this example will not compile due to triple(forceUnwrapping:)
expecting an Int
. It is easy to imagine a Swift beginner writing code that looks like this to "fix" the problem:
func triple(forceUnwrapping aNumber: Int!) -> Int {
return aNumber * 3
}
let possiblyNil = Int("foo")
triple(forceUnwrapping: possiblyNil)
While this version compiles, it crashes due to the force unwrapping of a nil
value. Unfortunately, the compiler "hides" this fact by making it seem like it's acceptable to pass in nil
–it doesn't make the forced unwrapping explicit.
A second, and deeper, issue is the fact that this sort of usage is an abuse of implicitly unwrapped optionals. From The Swift Programming Language:
Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the Optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time.
These kinds of optionals are defined as implicitly unwrapped optionals…
…Implicitly unwrapped optionals are useful when an Optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization…
As such, it can be said that an implicitly unwrapped optionals are a sort of agreement that while it may not have a value at initialization, by the time it is used it must have a valid value. If there is any doubt that a value will be nil
during its lifetime, it should be declared an Optional, to make this uncertainty explicit. As parameters and return values can not enforce this "guarantee", they should be restricted to only allowing non-Optionals and Optionals, depending on whether the value can be nil
.
The safest solution, in this case, is to prevent the use of implicitly unwrapped optionals in function signatures. By forcing users to write
func triple(forceUnwrapping aNumber: Int) -> Int {
return aNumber * 3
}
or
func triple(forceUnwrapping aNumber: Int?) -> Int {
return aNumber * 3
}
the compiler will complain, reminding users that they should probably attempt to safely unwrap the Optional before using it, as well as making the implicitly unwrapped optional "contract" binding.
The proposal will prevent the use of implicitly unwrapped optionals in function signatures for both Swift code as well as imported Objective-C code. As non-annotated Objective-C functions are currently imported as implicitly unwrapped, they will be converted to Optionals as a preliminary step. Non-audited frameworks can be reviewed in the future so that they can be tagged with _Nonnull
if necessary.
This proposal is a potentially source breaking change, but it should be easily mitigated using a migrator. Existing functions with implicitly unwrapped optionals can be changed to Optional; users can easily shadow variables with a guard
or change their function to non-Optional. Objective-C frameworks without Nullability annotations will be imported as Optionals, again requiring that users handle nil
properly (which they should be doing anyways, but if they aren't it serves as a good reminder).
Importing Objective-C functions as-is (that is, with implicitly unwrapped optionals), but disallowing implicitly unwrapped optionals in Swift code
This reduces the burden on existing frameworks and adding Nullability annotations, but creates a sort of disconnect between Objective-C and Swift in that it prevents Swift developers from writing functions signatures with implicitly unwrapped optionals.
Obviously, this has the benefit of keeping the current behavior and not requiring a migrator or any source changes. However, I believe that the unsafe behavior that this encourages is not worth keeping.
In my fork update author and link to mail discussion.