[swift-evolution] [Mini-proposal] Require @nonobjc on members of @objc protocol extensions

Douglas Gregor dgregor at apple.com
Tue Jan 5 11:58:38 CST 2016


> On Jan 5, 2016, at 3:40 AM, Andrew Bennett <cacoyi at gmail.com> wrote:
> 
> I'm on the fence here, I think it's a good solution if a project has ongoing objc dependencies.

If the Objective-C runtime is there, you have ongoing Objective-C dependencies: we call them Cocoa and Cocoa Touch ;)

> 
> However I have a few issues/suggestions:
> 
> 1) If a project is iteratively migrating from objc to swift, as I'm sure many are (a large project I'm working on included), then it would make that job much more tedious and increase the objc footprint in the swift code.

I don’t know what you mean by this. Your Objective-C code doesn’t contain protocol extensions, and the incremental cost to writing @nonobjc for members of extensions of @objc protocols (or accepting the Fix-It) is trivial.

> 
> 2) A linter could help me slowly remove unnecessary side-effects of this proposal, but it's not ideal, and it does not solve the large amounts of annotations needed to do so.

You’re worried about migrating an @objc protocol to a non- at objc protocol, and it has so many protocol extensions that the cost of removing the @nonobjc (or accept the Fix-It) is prohibitive? That seems very, very unlikely to me.

> 
> 3) If this proposal went ahead would existing code be migrated to add the annotation everywhere? (to retain equivalence)

Yes, where “everywhere” == “extensions of @objc protocols”.

> 
> 4) Have you explored any alternatives?
>  * instead of defaulting to @objc require an explicit @objc or @nonobjc, otherwise have a compile-time warning; default to @nonobjc still (for consistency).
>  * @objc(inherit=false)
> when put on the protocol it disables what you propose, inherit is true by default.
>  * compile time feedback:
>     + An objc compile time warning/error suggesting you add @objc if there's no matching selector, but there is a swift method.
> This may only work in whole module optimisation, also the dynamic nature of objc may prevent it from being deterministic.
>     + A swift compile time warning/error suggesting you add @objc if there's an objc protocol and an unannotated swift implementation.
> If I remember correctly something like this may already exist.

The idea of eliminating the blanket @objc default in subclasses of Objective-C-defined classes has come up. It would require us to infer ‘@objc’ in more places (and you noted), and would obviate the need for my proposal because the expectation of @objc-by-default would go away. That is a *much* larger and more interesting discussion.

	- Doug

> 
> 
> 
> On Tue, Jan 5, 2016 at 4:02 PM, Douglas Gregor via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> 
>> On Jan 4, 2016, at 8:58 PM, John Joyce <uchuugaka at icloud.com <mailto:uchuugaka at icloud.com>> wrote:
>> 
>> Would it not be possible to do the relative analog of Objective-C nullability macro sandwiches in Swift?
>> And then allowing exceptions within the file to be called out explicitly with @nonobjc or @objc ?
>> @begin_assume_nonobjc
>> @end_assume_nonobjc
>> @begin_assume_objc
>> @begin_assume_objc
> 
> Ick :)
> 
> If we need to annotate several things at once, doing it an extension granularity is good enough, because there’s essentially no cost to merging or breaking apart extensions as needed.
> 
> 	- Doug
> 
>>> On Jan 5, 2016, at 1:54 PM, Kevin Lundberg via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> I like this idea, but I would imagine that for an extension with many functions in it, requiring @nonobjc on each one would get tedious very fast. Could it be required (or at least allowed in addition to per-method annotations) at the extension level?:
>>> 	
>>> 	@objc protocol P {}
>>> 	
>>> 	@nonobjc extension P {
>>> 		func foo() { }
>>> 		func bar() { }
>>> 		func baz() { }
>>> 		func blah() { }		
>>> 		// etc...
>>> 	}
>>> 
>>> I don’t know if this would have specific implementation ramifications over only doing this on each method, if extensions cannot already be modified with attributes. I can’t think of a case where I’ve seen annotations added to protocol extensions, or any other extensions for that matter.
>>> 
>>> 
>>>> On Jan 4, 2016, at 11:32 PM, Douglas Gregor via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>> 
>>>> Hi all,
>>>> 
>>>> We currently have a bit of a surprise when one extends an @objc protocol:
>>>> 
>>>> @objc protocol P { }
>>>> 
>>>> extension P {
>>>>   func bar() { }
>>>> }
>>>> 
>>>> class C : NSObject { }
>>>> 
>>>> let c = C()
>>>> print(c.respondsToSelector("bar")) // prints "false"
>>>> 
>>>> because the members of the extension are not exposed to the Objective-C runtime. 
>>>> 
>>>> There is no direct way to implement Objective-C entry points for protocol extensions. One would effectively have to install a category on every Objective-C root class [*] with the default implementation or somehow intercept all of the operations that might involve that selector. 
>>>> 
>>>> Alternately, and more simply, we could require @nonobjc on members of @objc protocol extensions, as an explicit indicator that the member is not exposed to Objective-C. It’ll eliminate surprise and, should we ever find both the mechanism and motivation to make default implementations of @objc protocol extension members work, we could easily remove the restriction at that time.
>>>> 
>>>> 	- Doug
>>>> 
>>>> [*] Assuming you can enumerate them, although NSObject and the hidden SwiftObject cover the 99%. Even so, that it’s correct either, because the root class itself might default such a method, and the category version would conflict with it, so...
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution <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 <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 <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160105/6dcfdef5/attachment.html>


More information about the swift-evolution mailing list