<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 14, 2016, at 6:32 PM, Kevin Ballard via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">On Wed, Dec 14, 2016, at 05:54 PM, Brian King wrote:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">Please no. Just because I have to subclass NSObject doesn't mean I want to discard the performance benefits of static dispatch, and it especially doesn't mean I want to actually change the semantics of method resolution. Taking an existing Swift class and changing its base class to NSObject should not change how its methods are dispatched.<br class=""></blockquote><br class="">Subclassing NSObject already changes how dispatch happens. NSObject<br class="">extensions will use message dispatch for instance. I really don't<br class="">think that table -&gt; message dispatch will result in a real life<br class="">performance impact, but I agree that consistency is valuable.<br class=""><br class="">The static dispatch upgrade loss is disappointing. In practice<br class="">however, I don't think that this has ever had an impact on my code. If<br class="">performance is a consideration, most people just drop NSObject. If you<br class="">are using NSObject, you are probably using it because of a large<br class="">objective-c code base, in which case, I don't think the profiler is<br class="">really going to notice the few statically dispatched functions.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Obj-C compatibility certainly is one reason to use NSObject, but perhaps a bigger reason is because you're subclassing some framework-provided class, like UIView or UIViewController. Just because I'm subclassing UIViewController doesn't mean I want my controller's API to be subject to Obj-C method dispatch unnecessarily.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>In addition to UIView[Controller]s, pure Swift projects may also inherit from NSObject extensively in order to provide delegates, support NSCoding, etc. It would be counter-intuitive to me for methods on these otherwise pure Swift classes to not be vtable/de-virtualizable functions.</div><br class=""><blockquote type="cite" class=""><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">And even in the cases where I'm subclassing NSObject for Obj-C compatibility, that doesn't mean that most of the calls to my object are coming from Obj-C. All that means is that at least one place my object is used is Obj-C, and 99% of the uses might be Swift. Or if I'm writing a library, it might mean that I simply want to preserve Obj-C compatibility in case a client wants it, even though I expect my clients to be primarily Swift (For example, this is how postmates/PMHTTP is written; Obj-C–compatible, but the expectation is most clients will probably be Swift).</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></blockquote><blockquote type="cite" class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">Interaction with Obj-C runtime machinery stuff like KVO should be opt-in. In Obj-C it's ad-hoc, many classes support it for properties but many also don't, and very few properties have their KVO conformance documented. I don't view having to mark my properties as `dynamic` to participate in KVO to be a problem with Swift but rather a feature. It tells the reader that this property supports KVO.<br class=""></blockquote><br class="">This is an interesting point, and it would be an interesting semantic.<br class="">However in practice, the majority of NSObject code is imported from<br class="">obj-c, and it's generated interface does not follow this convention.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Just because framework classes don't follow this convention doesn't mean it's not a valuable convention to have in code written in Swift. There's a lot of things that Swift does better than Obj-C, and that you don't get when using an API imported from Obj-C, but that's not a reason to not do those things.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Also, it's strange to conflate how something was dispatched and if it<br class="">supported KVO. I think property delegates will be the future here and<br class="">enable some exciting contracts if adopted.<br class=""><br class="">Another approach is to just make it easier to opt into the full obj-c<br class="">machinery. The addition of a class or extension level `dynamic`<br class="">keyword would be great. If we could get buy in on this, then the<br class="">debate becomes if NSObject should default to `dynamic` or not.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>You would want a class-level `dynamic` that would also implicitly apply to any subclasses? This feels a little different than how Swift normally chooses defaults, could you elaborate more on why or if there’s anything else in the language analogous to this?</div><br class=""><blockquote type="cite" class=""><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">I don't think we should ever make it possible to mark an entire class as `dynamic`. This just reintroduces the Obj-C problem, where many properties support KVO, but not all, and there's no indication on the property itself as to whether it supports it.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>I’m not familiar enough with these kinds of bugs. Kevin, do you think the existing behavior aligns with or runs counter to safe-by-default?</div><br class=""><blockquote type="cite" class=""><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">-Kevin Ballard</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Brian<br class=""><br class=""><blockquote type="cite" class=""><br class="">-Kevin Ballard<br class=""><br class="">On Wed, Dec 14, 2016, at 03:15 PM, Brian King via swift-evolution wrote:<br class=""><blockquote type="cite" class="">I wanted to follow up to a blog post I wrote about Message Dispatch in<br class="">Swift — <a href="https://www.raizlabs.com/dev/2016/12/swift-method-dispatch" class="">https://www.raizlabs.com/dev/2016/12/swift-method-dispatch</a>. I<br class="">mentioned some changes to NSObject that didn’t result in any<br class="">objections, so I thought it was time to see what the SE mailing list<br class="">thought.<br class=""></blockquote></blockquote></blockquote></div></blockquote><div><br class=""></div><div>That’s a very thoughtful and informative post, thank you for writing it! I haven’t read the whole thing, but relevant to this, here are a couple tweaks:</div><div><br class=""></div><div><ul style="margin: 15px 0px; padding: 0px; box-sizing: border-box; color: rgb(51, 51, 51); font-family: proxima-nova-alt, helvetica, sans-serif; font-size: 18px;" class=""><li style="margin: 0px 0px 0px 20px; padding: 5px 0px; box-sizing: border-box; position: relative;" class=""><code style="margin: 0px; padding: 2px 4px; box-sizing: border-box; font-size: 16px; background-color: rgb(239, 239, 239); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px;" class="">NSObject</code>&nbsp;uses table dispatch for methods inside the initial declaration!</li></ul><div class="">I don’t think NSObject does, but native Swift subclasses of NSObject do by default, just like any other native Swift class or subclass.</div><div class=""><br class=""></div><div class=""><ul style="margin: 15px 0px; padding: 0px; box-sizing: border-box; color: rgb(51, 51, 51); font-family: proxima-nova-alt, helvetica, sans-serif; font-size: 18px;" class=""><li style="margin: 0px 0px 0px 20px; padding: 5px 0px; box-sizing: border-box; position: relative;" class=""><code style="margin: 0px; padding: 2px 4px; box-sizing: border-box; font-size: 16px; background-color: rgb(239, 239, 239); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px;" class="">NSObject</code>&nbsp;extensions use message dispatch</li></ul></div><div class="">Is this also true of extensions to native Swift subclasses of NSObject? I would assume that they would be static dispatch like any other method in an extension of a native Swift class or subclass.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><span style="color: rgb(51, 51, 51); font-family: proxima-nova-alt, helvetica, sans-serif; font-size: 18px; background-color: rgb(255, 255, 255);" class="">Above, I mentioned that methods defined inside the initial declaration of an&nbsp;</span><code style="margin: 0px; padding: 2px 4px; box-sizing: border-box; font-size: 16px; background-color: rgb(239, 239, 239); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; color: rgb(51, 51, 51);" class="">NSObject</code><span style="color: rgb(51, 51, 51); font-family: proxima-nova-alt, helvetica, sans-serif; font-size: 18px; background-color: rgb(255, 255, 255);" class="">subclass use table dispatch. I find this to be confusing, hard to explain</span></div><div class=""><br class=""></div><div class="">If anything, it seems consistent with how all native Swift classes operate. Knowing the entire transitive inheritance graph for a given class to know whether the default dispatch rules don’t apply seems more confusing and harder to explain. Could you elaborate?</div><div class=""><br class=""></div><div class="">What’s confusing might depend on one’s starting point. My perspective is from learning Swift and then learning Cocoa, and that’s why I see this behavior as being pretty consistent with Swift. But, maybe someone who knows Cocoa and is learning Swift might be confused?</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><br class="">I’ve read a few conversations on SE mailing list that have morphed<br class="">into abstract conversations about dynamic vs static dispatch. I want<br class="">to focus specifically on how Swift NSObject subclasses behave.<br class=""><br class="">I think that there are 2 changes that will result in fewer bugs and<br class="">will not have a substantial impact on performance:<br class=""><br class=""><br class="">## Remove Table Dispatch from NSObject<br class=""><br class="">NSObject subclasses use table dispatch for the initial class<br class="">declaration block. I think that using message dispatch for NSObject<br class="">subclasses everywhere will result in a much more consistent developer<br class="">experience.<br class=""><br class="">## Block NSObject Visibility Optimizations<br class=""><br class="">Swift upgrades method dispatch to final when the compiler can prove<br class="">that the method is not subclassed. I would like to see Swift be more<br class="">careful about the impact of these optimizations on message dispatch,<br class="">and consider message dispatch non-upgradable.<br class=""><br class=""></blockquote></blockquote></blockquote></div></blockquote><div><br class=""></div><div>My understanding is that Swift already considers message dispatch to be "non-upgradable". It seems like what you’re asking for is more like an implicitly inferred `dynamic` on all methods for subclasses of Objective-C classes.</div><br class=""><blockquote type="cite" class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><br class="">I thought it would help to frame this choice as a trade-off between<br class="">Swift’s goals of safe, fast, and expressive.<br class=""><br class="">## Safe<br class=""><br class="">Always using message dispatch for NSObject subclasses will fix a class<br class="">of runtime errors in framework features that are designed around<br class="">message passing (e.g. KVO). Arguments against using dynamic features<br class="">like this are valid, but Cocoa frameworks still use dynamic features<br class="">and the above behaviors result in actual bugs. As a bonus, this will<br class="">resolve SR-584, where a table-dispatched method that is overridden by<br class="">a message dispatch method doesn’t behave correctly.<br class=""><br class=""></blockquote></blockquote></blockquote></div></blockquote><blockquote type="cite" class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">## Fast<br class=""><br class="">The above changes will result in slower dispatch in NSObject<br class="">subclasses. However, I don't think that these dispatch changes<br class="">actually have a tangible impact on performance. Most NSObject<br class="">subclasses sit on top of a lot of `objc_msgSend`, and if there is a<br class="">specific hot spot, it would still be optimizable via the final<br class="">keyword.<br class=""><br class=""></blockquote></blockquote></blockquote></div></blockquote><div><br class=""></div><div>In the case of deriving from NSObject to be able to work with NSCoding, the only msgSending it sits on top of may be at relatively rare serialization points.</div><br class=""><blockquote type="cite" class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">## Expressive<br class=""><br class="">Using table dispatch for NSObject without any source indication or<br class="">library documentation is not very expressive. I think it’s important<br class="">to weigh table dispatch behavior against all of the framework<br class="">documentation and developer experience that assume message dispatch.<br class="">This will also eliminate the need for a lot of `@objc` and `dynamic`<br class="">annotations that are often inconsistently applied depending on if they<br class="">are needed in the scope they are defined in (e.g. class vs extension).<br class=""><br class=""><br class="">If this idea shows promise, I’d be glad to formalize a Swift Evolution<br class="">Proposal and explore syntactic details. I think being able to flag a<br class="">class with `dynamic` and applying this flag to `NSObject` may be the<br class="">only syntactic change needed. However, it would be good to debate the<br class="">merit of the behavior change before the syntax.<br class=""><br class=""><br class="">Thanks!<br class=""><br class=""><br class="">Brian King<br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></blockquote>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></blockquote></blockquote><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">_______________________________________________</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">swift-evolution mailing list</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a></span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span></div></blockquote></div><br class=""></body></html>