> On Jan 6, 2017, at 3:46 AM, Rod Brown <[email protected]> wrote:
> 
>> 
>> On 5 Jan 2017, at 11:50 am, Douglas Gregor via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> 
>> Hi all,
>> 
>> Here’s a draft proposal to limit inference of @objc to only those places 
>> where we need it for consistency of the semantic model. It’s in the realm of 
>> things that isn’t *needed* for ABI stability, but if we’re going to make the 
>> source-breaking change here we’d much rather do it in the Swift 4 time-frame 
>> than later. Proposal is at:
>> 
>>      
>> https://github.com/DougGregor/swift-evolution/blob/objc-inference/proposals/NNNN-objc-inference.md
>>  
>> <https://github.com/DougGregor/swift-evolution/blob/objc-inference/proposals/NNNN-objc-inference.md>
>> 
> 
>>  
>> <https://github.com/DougGregor/swift-evolution/tree/objc-inference#source-compatibility>Source
>>  compatibility
>> 
>> The two changes that remove inference of @objc are both source-breaking in 
>> different ways. The dynamic change mostly straightforward:
>> 
>> In Swift 4 mode, introduce an error that when a dynamic declaration does not 
>> explicitly state @objc, with a Fix-It to add the @objc.
>> 
>> In Swift 3 compatibility mode, continue to infer @objc for dynamic methods. 
>> However, introduce a warning that such code will be ill-formed in Swift 4, 
>> along with a Fix-It to add the @objc. This
>> 
>> A Swift 3-to-4 migrator could employ the same logic as Swift 3 compatibility 
>> mode to update dynamic declarations appropriately.
>> 
>> The elimination of inference of @objc for declarations in NSObject 
>> subclasses is more complicated. Considering again the three cases:
>> 
>> In Swift 4 mode, do not infer @objc for such declarations. Source-breaking 
>> changes that will be introduced include:
>> 
>> If #selector or #keyPath refers to one such declaration, an error will be 
>> produced on previously-valid code that the declaration is not @objc. In most 
>> cases, a Fix-It will suggest the addition of @objc.
>> 
>> The lack of @objc means that Objective-C code in mixed-source projects won't 
>> be able to call these declarations. Most problems caused by this will result 
>> in warnings or errors from the Objective-C compiler (due to unrecognized 
>> selectors), but some might only be detected at runtime. These latter cases 
>> will be hard-to-detect.
>> 
>> Other tools and frameworks that rely on the presence of Objective-C 
>> entrypoints but do not make use of Swift's facilities for referring to them 
>> will fail. This case is particularly hard to diagnose well, and failures of 
>> this sort are likely to cause runtime failures that only the developer can 
>> diagnose and correct.
>> 
>> In Swift 3 compatibility mode, continue to infer @objc for these 
>> declarations. When @objc is inferred based on this rule, modify the 
>> generated header (i.e., the header used by Objective-C code to call into 
>> Swift code) so that the declaration contains a "deprecated" attribute 
>> indicating that the Swift declaration should be explicitly marked with 
>> @objc. For example:
>> 
>> class MyClass : NSObject {
>>   func foo() { }
>> }
>> will produce a generated header that includes:
>> 
>> @interface MyClass : NSObject
>> -(void)foo NS_DEPRECATED("MyClass.foo() requires an explicit `@objc` in 
>> Swift 4");
>> @end
>> This way, any reference to that declaration from Objective-C code will 
>> produce a warning about the deprecation. Users can silence the warning by 
>> adding an explicit @objc.
>> 
>> A Swift 3-to-4 migrator is the hardest part of the story. Ideally, the 
>> migrator to only add @objc in places where it is needed, so that we see some 
>> of the expected benefits of code-size reduction. However, there are two 
>> problems with doing so:
>> 
>> Some of the uses that imply the need to add @objc come from Objective-C 
>> code, so a Swift 3-to-4 migrator would also need to compile the Objective-C 
>> code (possibly with a modified version of the Objective-C compiler) and 
>> match up the "deprecated" warnings mentioned in the Swift 3 compatibility 
>> mode bullet with Swift declarations.
>> 
>> The migrator can't reason about dynamically-constructed selectors or the 
>> behavior of other tools that might directly use the Objective-C runtime, so 
>> failing to add a @objc will lead to migrated programs that compile but fail 
>> to execute correctly.
>> 
>> 
> Yeah, this is definitely a point of concern. I’m not sure that the first part 
> deals with stuff like frameworks and libraries that currently expose 
> functionality to external users in Obj-C. How could you be sure which API was 
> designed to be used by Obj-C when it comes to libraries?

It is *very* hard to know.

> As others have mentioned, perhaps we could have options in the converter? I’m 
> not generally a fan of this type of preference selection but in this case it 
> seems reasonable.

Yeah, maybe. Designing the migrator itself isn’t really in the scope of the 
Swift evolution process, but we do appreciate hearing people’s ideas here. It’s 
a tough thing to migrate well.

> The dynamically constructed selector case seems rare, especially considering 
> that using string-based selectors has been deprecated since Swift 2.2.

I suspect that you are right that failures would be rare. It’s the 
>>  
>> <https://github.com/DougGregor/swift-evolution/tree/objc-inference#overriding-of-declarations-introduced-in-class-extensions>Overriding
>>  of declarations introduced in class extensions
>> 
>> There are several potential solutions to this problem, but both are 
>> out-of-scope for this particular proposal:
>> 
>> Require that a non-@objc declaration in a class extension by explicitly 
>> declared final so that it is clear from the source that this declaration 
>> cannot be overridden.
>> 
>> Extend Swift's class model to permit overriding of declarations introduced 
>> in extensions.
>> 
>> 
> I will definitely be running into this issue if/when this occurs. A lot of 
> users use extensions to break up their code into clear elements for 
> organisational reasons, and also adding functionality to external libraries. 
> Both here would end up with odd behaviour and I really hope we go with Option 
> 2 here.

Either option requires a proposal; Option 2 can certainly have ABI impact 
because it could effect the ABI of Swift classes.

As an aside, we/I realized belatedly that this proposal obviously doesn’t fit 
Swift 4 stage 1, so we’ll hold off on the review until we open up stage 2.

        - Doug

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to