[swift-evolution] SR-104: Improve Crash-Safety when Importing Objective-C Code Without Nullability Attributes

Fabian Ehrentraud Fabian.Ehrentraud at willhaben.at
Thu Dec 10 15:22:51 CST 2015


Too bad to hear you are opposed to the change.
Thank you for the hint at the API dumps - this is really something that should be referenced in the proposal.

> First of all, this affects a lot of APIs. I went ahead and grepped through the API dumps [...] to see how often implicitly-unwrapped optionals came through in the Cocoa APIs, and there are lots of them. For example, on OS X, grepping for !’s finds:

We should come to a common way to count the occurrences of affected APIs (despite that users would also need to adapt for un-annotated 3rd-party frameworks, and the own mixed&matched application code).
When I counted, it resulted in less than half the numbers for initializers and functions/methods.

There are many comment lines in the API dumps that contain /*! - we should not count those.
Also for functions/methods, input-parameters do not matter, due to automatic Optional wrapping on the Swift side. Maybe closure parameters that have implicitly unwrapped optional arguments themselves should be counted too. (anything else?)

Initializers:

Should we only count "init!" instances?
$ grep init! . | wc -l
=> OSX 152, iOS 42

Other initializers containing ! in another place (I guess not relevant for the proposal)
$ grep -r ! . | grep init | grep -v '\/\*\!' | grep -v init!

Functions/Methods:

Only counting those that have a return type with an implicitly unwrapped optional. This does not take into account closure parameters that have implicitly unwrapped optional arguments themselves though.
$ grep -r ! . | grep func | grep '\->' | grep -v '\/\*\!' | grep -e '\!$' | wc -l
=> OSX 1577, iOS 452

Properties:

$ grep -r ! . | grep -e "let " | grep -v '\/\*\!' | wc -l
=> OSX 1120, iOS 336

Constants:

I noticed there are many constants that get translated to implicitly unwrapped optionals (e.g. in iOS CoreFoundation.swift). Would they be affected by the change in this proposal? Or are they "explicitly set to implicitly unwrapped" by the importer?


> Most of the implicitly unwrapped optionals we currently get from (Objective-)C APIs can, in fact, never be nil. Forcing programmers to deal with all of these values as full optionals leads to a ton of optional-related boilerplate that doesn’t actual help users write better code. Rather, it dilutes the effectiveness of optionals as a language feature: optionals should mean “nil matters here, think about it carefully!”. But if some large number of optionals people deal with on a day-to-day basis are instead “the compiler didn’t know, so you have to write !”, the useful meaning of the “true” optionals gets lost in the noise.

I think exactly the opposite. If an API has not yet been audited, the client needs to consult the documentation if a return value can ever be nil. If not, she might explicitly and knowingly unwrap the value safely or non-safely. I deem this a good thing, as it prevents unknowingly unsafe use. I do not think that it would get in the way, as the syntactic sugar for Optionals is quite minimal. Also when the API gets audited for nullability later on, the compiler will hint which optional unwrappings have been rendered unnecessary.



> On 10.12.2015, at 19:27, Douglas Gregor <dgregor at apple.com> wrote:
> 
> 
>> On Dec 10, 2015, at 3:42 AM, Fabian Ehrentraud via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> Are there any objections to variant 2 "Import un-annotated code as Optional"? If not, I would create the proposal. 
> 
> I’m opposed to this. 
> 
> First of all, this affects a lot of APIs. I went ahead and grepped through the API dumps over at
> 
> 	https://github.com/apple/swift-3-api-guidelines-review
> 
> to see how often implicitly-unwrapped optionals came through in the Cocoa APIs, and there are lots of them. For example, on OS X, grepping for !’s finds:
> 
> 	4132 functions/methods
> 	2281 properties
> 	409 initializers
> 
> On iOS, which has a smaller number of overall APIs, the numbers are still pretty big:
> 	1071 functions/methods
> 	320 properties
> 	134 initializers
> 
> This may be a slight oversampling of the data—some of those might be explicitly annotated as _Null_unspecified in the (Objective-)C headers, some might be unavailable—but the scale of the impact here is very, very large.
> 
> Most of the implicitly unwrapped optionals we currently get from (Objective-)C APIs can, in fact, never be nil. Forcing programmers to deal with all of these values as full optionals leads to a ton of optional-related boilerplate that doesn’t actual help users write better code. Rather, it dilutes the effectiveness of optionals as a language feature: optionals should mean “nil matters here, think about it carefully!”. But if some large number of optionals people deal with on a day-to-day basis are instead “the compiler didn’t know, so you have to write !”, the useful meaning of the “true” optionals gets lost in the noise.
> 
> That said, I’d love for implicitly-unwrapped optionals to be used less often, and getting them further out of the type system would be beneficial for the Swift experience.
> 
> 	- Doug
> 
>> 
>>> Am 09.12.2015 um 07:11 schrieb Chris Lattner <clattner at apple.com>:
>>> 
>>> 
>>>> On Dec 8, 2015, at 4:09 AM, Fabian Ehrentraud via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> Swift code accessing Objective-C methods can easily crash - if the Objective-C code does not include nullability attributes, the code is brought as implicitly unwrapped into Swift, where unsafe accesses do not produce compiler warnings.
>>>> 
>>>> I created issue SR-104 for this, but as suggested by Jordan Rose it should be discussed on this mailing list first.
>>>> 
>>>> Short example:
>>>> 
>>>> // Objective-C  
>>>> - (NSString *)giveMeAString { return nil; }  
>>>> 
>>>> // Swift  
>>>> func thisWillCrash() {  
>>>> let string = someObjectiveCObject.giveMeAString()  
>>>> let length = string.length // crash  
>>>> }
>>>> 
>>>> The ClangImporter could handle this issue in several safer ways:
>>>> 
>>>> 1. Only import declarations that are nullability annotated (as proposed by Greg Parker)
>>>> Positive side effect would be that it would motivate to write nullability annotations.
>>> 
>>> This seems unfortunate to me, because it would severely hamper interoperating with Objective-C and *C* APIs that have not been audited.  While Apple is keen to audit their APIs, I doubt that all the linux system headers will get updated in a timely manner and users don’t generally have a way to do anything about that.
>>> 
>>>> 2. Import un-annotated code as Optional
>>>> Values would need to be unwrapped every time, which does not hurt too much due to the easy use of the `?` syntactic sugar.
>>> 
>>> This is a very interesting idea, one I haven’t considered recently.  I agree with you that this is worth considering, and I would love to see IUO just get summarily deleted :-)
>>> 
>>> -Chris
>> _______________________________________________
>> 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