[swift-evolution] [Proposal draft] Limiting @objc inference
dgregor at apple.com
Thu Jan 5 13:48:50 CST 2017
> On Jan 5, 2017, at 9:30 AM, Brian King <brianaking at gmail.com> wrote:
> +1, I really like the consistency. There's still one potential inconsistency that I think could be changed to improve things
> Overriding of declarations introduced in class extensions
> The inference of @objc inside extensions in Swift 3 is more than visibility to the Obj-c runtime, it also infers `dynamic`. This proposal appears to retain that, since `@objc` in an extension would allow override via message dispatch, where as `@objc` in a class declaration would only make the selector available to the obj-c runtime and retain table dispatch.
Excellent point! I’d come across the `dynamic` inference while writing this proposal, but had deluded myself into thinking that it was just an implementation detail. You’re right that it surfaces in the user model.
> Does it make sense to remove the `dynamic` inference too? This would force all extension methods that can be overridden to be declared `@objc dynamic`. This clarifies the purpose of @objc since it only manages Obj-C visibility, and does not modify dispatch behavior.
The practical effect of removing `dynamic` inference is that a declaration introduced in a class extension can only be overridden if it is marked
Overriding declarations won’t have to repeat this utterance (“override” suffices), so the boilerplate is restricted to the introduction of the first overridable declaration.
I guess the specific rule would be that @objc declarations introduced in a class extension must either be ‘dynamic’ or ‘final’, with the subtle-but-understandable annoyance that ‘final’ methods can still be swizzled by the Objective-C runtime.
I definitely need to mention this in the proposal (thank you!), but I’m on the fence regarding whether to propose doing anything about it in this specific proposal. I already intentionally subsetted out the other part of the overrides-of-declarations-in-extensions issue (see the section “Overriding of declarations introduced in class extensions”), and it feels like the issues should be tackled together.
Part of me also wonders whether it’s worth this level of boilerplate now to save on an expected-to-be-small amount of breakage later. Specifically, we’re talking about cases where the user swizzled a method but didn’t mark it ‘dynamic’. Or, swizzled a method that was explicitly marked ‘final’, which the runtime doesn’t know. There are numerous other failure cases here where one has swizzled a method via the Objective-C runtime such that only Objective-C callers invoke the new method, but Swift callers invoke the pre-swizzled version. Personally, I think we can address this problem holistically by teaching the Objective-C runtime about Swift’s thunks so it can warn when swizzling non-‘dynamic’ ones, which would obviate the need for explicit ‘dynamic’ in these cases.
> I know this departs from my previous "NSObject should stay dynamic" argument earlier, but I was mostly arguing for consistency. Since it is clear that dynamic behavior should be opted into, I think forcing an additional `dynamic` keyword seems to make sense. Some developers may rely on this implicit `dynamic` behavior and encounter issues if a future version of swift allows overrides in extensions via table dispatch.
We’re both seeking a more consistent and predictable model, but we’re going in different directions. I feel that my proposal is more in line with the direction Swift has been going.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution