[swift-evolution] [Proposal] Remove force unwrapping in function signature.

Vladimir.S svabox at gmail.com
Wed Jun 29 06:40:48 CDT 2016


On 29.06.2016 6:57, Chris Lattner via swift-evolution wrote:
>
>> On Jun 27, 2016, at 4:42 PM, Saagar Jha via swift-evolution
>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>
>> Alright, I’ve written it up a proposal; you can find it here
>> <https://gist.github.com/saagarjha/f33fecd4576f40133b6469da942ef453>.
>> This is my first proposal (and anyways I’ve been told that I can be
>> unclear), so if you guys see anything that should be changed feel free to
>> let me know. Here it is inline:
>>
> Hi Saagar,
>
> If I understand your proposal correctly, you are suggesting that we remove
> T! and just force people to use T? or T.  This is a commonly rejected

As I understand, Saagar suggests to disallow T! for function parameters 
only. And allow only T or T?.

About the API, as I understand, the suggestion is to explicitly use guard:

func someAPIFunc(t: T?) {
     guard let t = t else { fatalError("t==nil was not expected in 
someAPIFunc") }

     // code of function
     print(t) // `t` is not optional here
}

 From one side this adds more boilerplate code for API functions, but from 
other - such function is very clear about the behavior in case of `nil` 
sent to such function. I.e. all is explicit and clear.  With IUO it is not 
obvious what will be the behavior if `nil` will be sent to func.
Personally I'm not sure if I'm +1 for this suggestion or -1.. Probably +1 
because of more obvious behavior and the fact that we can have more 
descriptive error in case of `nil` in such function.

> proposal (though not on the list yet) that frequently comes up.  The
> problem with your proposal is that you don’t provide any solutions to the
> problems that T! is currently solving: that of two-phase initialization and
> importing of APIs that have not been nullability audited.  It isn’t
> pragmatic to handle these cases as T?
>
> -Chris
>
>>
>>   Remove implicitly unwrapped optionals as function parameters
>>
>>   * Proposal: SE-NNNN
>>     <x-msg://38/NNNN-remove-implicitly-unwrapped-function-parameters.md>
>>   * Author: Swift Developer <https://github.com/swiftdev>
>>   * Status: *Awaiting review*
>>   * Review manager: TBD
>>
>>
>>     Introduction
>>
>> 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
>> <https://developer.apple.com/swift/blog/?id=25> 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 as function parameters*.
>> Discussion on this topic may be found here
>> <http://article.gmane.org/gmane.comp.lang.swift.evolution/21730/>.
>>
>>
>>     Motivation
>>
>> 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*.
>>
>>
>>     Proposed solution
>>
>> The safest solution, in this case, is to prevent the use of implicitly
>> unrwapped 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.
>>
>>
>>     Detailed design
>>
>> 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 audited in the future so
>> that they can be tagged with |_Nonnull| if necessary.
>>
>>
>>     Impact on existing code
>>
>> This is a proposal is a 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.
>>
>>
>>     Alternatives considered
>>
>>
>>       Importing Objective-C functions as-is, but disallowing implictly
>>       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 with
>> implicitly unwrapped optionals.
>>
>>
>>       Doing nothing
>>
>> Obviously, this has the benefit of keeping the current behavior and not
>> requiring a migrator. However, I believe that the unsafe behavior that
>> this encourages is not worth keeping.
>>
>>
>>
>> On Mon, Jun 27, 2016 at 1:35 PM Dennis Lysenko
>> <dennis.s.lysenko at gmail.com <mailto:dennis.s.lysenko at gmail.com>> wrote:
>>
>>     +1. This is sort of how Kotlin does it. In Kotlin, IUOs are strictly
>>     a carryover from Java. They show up in method signatures from
>>     non-nullable-annotated Java, but you can't define a new method that
>>     takes e.g. an Int!.
>>
>>     The limited scope of this proposal is ideal in my opinion since we
>>     see areas where IUOs are clearly useful (ViewControllers for
>>     instance) but defining new functions that take implicitly unwrapped
>>     optionals makes no sense. If you need to pass a IUO at the call site,
>>     you can define the function taking a non-optional value and pass the
>>     IUO to that. There is no use case I can think of for having it in
>>     method/function signatures.
>>
>>     RE: language inconsistencies, there is no such issue in practice in
>>     Kotlin where there is also inconsistency in the same vein. I see it
>>     simply as a compromise that achieves the goal of keeping a useful
>>     feature but discouraging its overuse by forbidding its use in places
>>     where its use could confuse and snowball down the line into teaching
>>     developers worse code quality.
>>
>>     On Mon, Jun 27, 2016 at 12:04 PM Charlie Monroe via swift-evolution
>>     <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>
>>         Ok, I see - though I find myself using occasionally IUOs in Swift
>>         as well - e.g. when you can't use the default values because they
>>         depend on self, etc.
>>
>>         Eliminating it just from method signatures IMHO brings an
>>         incosistency into the language. Why would you eliminate it only
>>         from method signatures - this proposal mentioned importing ObjC
>>         API in the beginning - why not then mark those properties all as
>>         optional as well? IUOs are scheduled to be removed completely
>>         once the language reaches a point where it can handle most
>>         scenarios otherwise...
>>
>>         Try to imagine some APIs brought to Swift with default being
>>         nullable:
>>
>>         /// Imported from
>>         publicclassNSOrderedSet : NSObject, NSCopying, NSMutableCopying,
>>         NSSecureCoding, NSFastEnumeration{
>>
>>             publicvarcount: Int{ get }
>>             publicfuncobjectAtIndex(idx: Int) -> AnyObject?
>>             publicfuncindexOfObject(object: AnyObject?) -> Int
>>             publicinit()
>>             publicinit(objects: UnsafePointer<AnyObject?>, count cnt: Int)
>>             publicinit?(coder aDecoder: NSCoder?)
>>         }
>>
>>         This doesn't make much sense - mostly objectAtIndex(_:).
>>
>>>         On Jun 27, 2016, at 8:35 PM, Saagar Jha <saagarjha28 at gmail.com
>>>         <mailto:saagarjha28 at gmail.com>> wrote:
>>>
>>>         I think you’re mistaking the scope of the proposal. It’s simply
>>>         removing IUOs in /function signatures/, not throughout the language.
>>>
>>>         On Mon, Jun 27, 2016 at 11:31 AM Charlie Monroe via
>>>         swift-evolution <swift-evolution at swift.org
>>>         <mailto:swift-evolution at swift.org>> wrote:
>>>
>>>             There are many useful cases for IUO in Swift - mostly when
>>>             you have variables that cannot be calculated at the point of
>>>             calling super.init(), but are guaranteed to be filled during
>>>             initialization - i.e. during the lifetime of the object, the
>>>             value is nonnil, but may be nil for a short period of time.
>>>
>>>             Or @IBOutlets. Making all @IBOutlets optionals would make
>>>             the code either riddled with ! or shadowed locally
>>>             re-declared instance members.
>>>
>>>
>>>             > On Jun 27, 2016, at 8:12 PM, Jean-Daniel Dupas
>>>             <mailing at xenonium.com <mailto:mailing at xenonium.com>> wrote:
>>>             >
>>>             > Maybe we can prohibit it in Swift function declaration,
>>>             and allow it only when importing native code.
>>>             >
>>>             > As David, I don’t see any compelling reason to allow such
>>>             construct in Swift.
>>>             >
>>>             >> Le 27 juin 2016 à 10:39, Charlie Monroe via
>>>             swift-evolution <swift-evolution at swift.org
>>>             <mailto:swift-evolution at swift.org>> a écrit :
>>>             >>
>>>             >> When you import ObjC code that has no nullability
>>>             annotation, IUO make sense since:
>>>             >>
>>>             >> - they can be checked against nil
>>>             >> - typically, most values in APIs are nonnull (looking at
>>>             Foundation, for example, which is why Apple has the
>>>             NS_ASSUME_NONNULL_BEGIN to mark entire regions as nonnull,
>>>             yet there is no NS_ASSUME_NULL_BEGIN)
>>>             >>
>>>             >> Importing them as optionals would make it really hard to
>>>             work with the code - whenever you get a value, it's an
>>>             optional, even in cases where it makes no sense and adding !
>>>             to unwrap the optional is not a great solution. And the
>>>             other solution is to use guards everywhere.
>>>             >>
>>>             >> IMHO the IUO is a nice (temporary) solution for using
>>>             un-annotated code until it is. But the "pressure" should be
>>>             applied on the ObjC code.
>>>             >>
>>>             >>> On Jun 27, 2016, at 10:03 AM, David Rönnqvist
>>>             <david.ronnqvist at gmail.com
>>>             <mailto:david.ronnqvist at gmail.com>> wrote:
>>>             >>>
>>>             >>> I don’t know about the chances of getting approved, but
>>>             I think this is something worth discussing.
>>>             >>>
>>>             >>> It might just be my ignorance, but I can’t think of a
>>>             good reason why a function argument would be force
>>>             unwrapped. Either it’s non-null and the caller is expected
>>>             to unwrap it or it’s nullable and the method is expected to
>>>             handle the nil value. So I’m positive to that part of the
>>>             proposal.
>>>             >>>
>>>             >>> As to what we should do with the generated interfaces of
>>>             Objective-C code that hasn’t been annotated with
>>>             nullability, I think that needs input from more people to
>>>             find the preferred solution.
>>>             >>>
>>>             >>> Once that’s been discussed some more, I’d be willing to
>>>             write up a formal proposal if you don’t feel like it
>>>             (assuming the discussion leads somewhere).
>>>             >>>
>>>             >>> - David
>>>             >>>
>>>             >>>
>>>             >>>> On 27 Jun 2016, at 06:28, Charlie Monroe via
>>>             swift-evolution <swift-evolution at swift.org
>>>             <mailto:swift-evolution at swift.org>> wrote:
>>>             >>>>
>>>             >>>> See
>>>             https://github.com/apple/swift-evolution/blob/master/process.md
>>>             - you would need to make an official proposal and submit it
>>>             as pull request. But given the reaction here, it's unlikely
>>>             to get approved.
>>>             >>>>
>>>             >>>> Also, the ObjC code without nullability is getting
>>>             fairly rare - all Apple's frameworks are with nullability
>>>             information (as far as I've checked) in macOS 10.12, iOS 10.
>>>             Third party libraries should be updated to use nullability
>>>             (and most libraries that are maintained already do).
>>>             >>>>
>>>             >>>>
>>>             >>>>> On Jun 25, 2016, at 5:13 PM, Spromicky via
>>>             swift-evolution <swift-evolution at swift.org
>>>             <mailto:swift-evolution at swift.org>> wrote:
>>>             >>>>>
>>>             >>>>> So, its proposal is dead, or what we must to do to
>>>             force it to swift-evolution repo on GitHub?
>>>             >>>>>
>>>             >>>>>> Hello, everyone!
>>>             >>>>>>
>>>             >>>>>> I wanna propose to you to remove force unwrapping in
>>>             fuction signature for swift code. That no sense in clear
>>>             swift code. If we wanna use some optional value as function
>>>             param, that is not optional, we must unwrap it before
>>>             function call.
>>>             >>>>>> People who new in swift look at how they old Obj-C
>>>             code (without nullability modifiers) translate in to swift:
>>>             >>>>>>
>>>             >>>>>> Obj-C:
>>>             >>>>>> - (void)foo:(NSInteger)bar {
>>>             >>>>>> //...
>>>             >>>>>> }
>>>             >>>>>>
>>>             >>>>>> Swift transaliton:
>>>             >>>>>> func foo(bar: Int!) {
>>>             >>>>>> //...
>>>             >>>>>> }
>>>             >>>>>>
>>>             >>>>>> And think that force unwrapping in signature is good
>>>             practice. And start write functions in clear swift code like
>>>             this:
>>>             >>>>>>
>>>             >>>>>> func newFoo(bar: Int!) {
>>>             >>>>>> //...
>>>             >>>>>> }
>>>             >>>>>>
>>>             >>>>>> and use it like this:
>>>             >>>>>>
>>>             >>>>>> let bar: Int? = 1
>>>             >>>>>> newFoo(bar)
>>>             >>>>>>
>>>             >>>>>> And it really work, and they does not think that this
>>>             can crash in case if `bar` will be `nil`.
>>>             >>>>>> But in clear swift we wanna work with parametrs in
>>>             function that clearly or optional, or not.
>>>             >>>>>>
>>>             >>>>>> func newFoo(bar: Int) {
>>>             >>>>>> //...
>>>             >>>>>> }
>>>             >>>>>>
>>>             >>>>>> or
>>>             >>>>>>
>>>             >>>>>> func newFoo(bar: Int?) {
>>>             >>>>>> //...
>>>             >>>>>> }
>>>             >>>>>>
>>>             >>>>>> When we write a new function we know what we need in
>>>             this case and use optional params or not.
>>>             >>>>>>
>>>             >>>>>> So my proposal is remove force unwrapping(`!`) from
>>>             function signatures, cause it have no sense, and that
>>>             confuse new users.
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>>>
>>>             >>>>> _______________________________________________
>>>             >>>>> swift-evolution mailing list
>>>             >>>>> swift-evolution at swift.org
>>>             <mailto:swift-evolution at swift.org>
>>>             >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>             >>>>
>>>             >>>> _______________________________________________
>>>             >>>> swift-evolution mailing list
>>>             >>>> swift-evolution at swift.org
>>>             <mailto:swift-evolution at swift.org>
>>>             >>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>             >>>
>>>             >>
>>>             >> _______________________________________________
>>>             >> swift-evolution mailing list
>>>             >> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>             >> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>             >
>>>
>>>             _______________________________________________
>>>             swift-evolution mailing list
>>>             swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>             https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>         --
>>>         -Saagar Jha
>>
>>         _______________________________________________
>>         swift-evolution mailing list
>>         swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>         https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>> --
>> -Saagar Jha
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>


More information about the swift-evolution mailing list