<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=""><div class="">What about this? I’m unfamiliar with the details of objc-swift interoperability, so I’m not actually sure it could work this way, nor am I certain that I’m not just “rephrasing” something that’s already been suggested.</div><div class=""><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> SomeProtocol {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">//Non-optional stuff goes here</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(41, 161, 152);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">extension</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">SomeProtocol</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">//Optional stuff goes here</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> blah() {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">//Default implementation goes here</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117); min-height: 15px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> SomeSubProtocol : </span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">SomeProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">//The same optional stuff goes here again</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> blah()</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117); min-height: 15px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> foo<T : </span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">SomeProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">> (x:</span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">T</span><span style="font-variant-ligatures: no-common-ligatures" class="">) {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(41, 161, 152);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">if</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">let</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> x = x </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">as</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class="">? </span><span style="font-variant-ligatures: no-common-ligatures" class="">SomeSubProtocol</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> x.</span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">blah</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class="">() </span><span style="font-variant-ligatures: no-common-ligatures" class="">//Is custom implementation because we know x is SomeOtherProtocol</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> } </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">else</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> x.</span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">blah</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class="">() </span><span style="font-variant-ligatures: no-common-ligatures" class="">//Is default implementation because we know it's not</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> ...</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">(It seems like there ought to be a less repetitive way to do the branch. The problem is that any expression would necessarily have to evaluate to two different types, depending on whether T conforms to the sub protocol.)</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">Anyway, does that correctly model the relationship between optional requirements and their protocols? I’ve used optional protocol requirements just enough to use UIKit and such, but I find the whole self-contradictional "optional requirement” thing confusing enough that I’ve never really felt like I understand them. There’s a fair chance that I’m missing their point.</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">If that is the correct model, is there a way to automatically create all the objc “subprotocols" as they’re being imported into swift? If so, would it be beneficial to maybe “nest” the protocols </span>to prevent UIKit from declaring 50 million “top level” protocols?</div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> SomeProtocol {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> SomeOtherProtocol { </span><span style="font-variant-ligatures: no-common-ligatures" class="">// the " : SomeProtocol" part is implied</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> blah() -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #278bd2" class="">Int</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">//Non-optional stuff goes here</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(41, 161, 152);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">extension</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">SomeProtocol</span><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(203, 75, 22);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #586e75" class=""> </span><span style="font-variant-ligatures: no-common-ligatures" class="">//Optional stuff goes here</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> blah() -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #278bd2" class="">Int</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #6c71c4" class="">5</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div class=""><div style="margin: 0px; line-height: normal;" class=""><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> blah<T : </span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">SomeProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">> (x:</span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">T</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #278bd2" class="">Int</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">if</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> x = x </span><span style="font-variant-ligatures: no-common-ligatures; color: #d33682" class="">as</span><span style="font-variant-ligatures: no-common-ligatures" class="">? </span><span style="font-variant-ligatures: no-common-ligatures; color: #29a198" class="">SomeProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #278bd2" class="">SomeOtherProtocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {…}</span></div><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(88, 110, 117);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div class=""><br class=""></div></div></div></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">- Dave Sweeris</span></div><div class=""><div style="margin: 0px; font-size: 14px; line-height: normal; font-family: Inconsolata; color: rgb(211, 54, 130);" class=""><div style="margin: 0px; line-height: normal;" class=""><br class=""></div></div></div><div class=""><div><blockquote type="cite" class=""><div class="">On Apr 13, 2016, at 12:47 AM, Douglas Gregor via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Apr 8, 2016, at 8:53 AM, Shawn Erickson <<a href="mailto:shawnce@gmail.com" class="">shawnce@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="white-space:pre-wrap" class="">I want to reiterate that I have objective-c code, others have objc code, and the cocoa, etc. frameworks have code that depend on optional protocol for things like (but not limited to) delegates. This is of course obvious but what seems to get lost in the discussion is that you can't always replace the non-existence of an implementation of an optional protocol method with a default implementation.<br class=""><br class="">I have code that probes a delegate when registered and based on the what subset of the optional protocol methods it handles configures its runtime state to optimize itself to that reality. For example it may avoid allocating and maintaining potentially complex state if one or more methods are not implemented by the delegate (since no one is interested in it). If we just blindly provide default implementation for optional methods then this optimization couldn't take place.<br class=""><br class="">I know others - including I believe Apple framework code - do similar optimizations based on what methods an object implements.<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">Just to be very clear (which I think my initial post wasn’t) my proposal does *not* break this optimization when a Swift class is conforming to an @objc protocol: even if a default is present, it won’t be visible to the Objective-C runtime at all.</div><div class=""><br class=""></div><div class="">My proposal *does* make it significantly harder to implement a check for “did the type implement this method?”, because one will effectively have to use -respondsToSelector:. For Cocoa-defined delegates, that doesn’t matter at all: apps generally implement requirements of delegates/data sources, but almost never go through the protocol to use those methods/properties. It’s the frameworks that do the calling, and of course they’re already using -respondsToSelector: checks.</div><div class=""><br class=""></div><div class="">The main effect is in Swift code that uses @objc optionals and tests for the absence of an implementation to perform some optimization. The tenor of the previous thread seems to indicate that this probably isn’t common, because there are probably better ways to model these cases in Swift—whether it’s with multiple protocols or something that specifically describes the policy (e.g., <a href="http://thread.gmane.org/gmane.comp.lang.swift.evolution/13347/focus=13480" class="">http://thread.gmane.org/gmane.comp.lang.swift.evolution/13347/focus=13480</a>).</div><div class=""><br class=""></div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div style="white-space:pre-wrap" class="">I think we should maintain the optional concept in support of bridging existing objc code into swift (confined to @objc)... unless a way to bridge things can be defined that avoids the loss of optimization potential I outlined above.<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">The direction I’m trying to go is not to have half of a feature—something that seems like it should be general, but is tied to @objc—in the language. We get a very large number of requests to make “optional” work for Swift protocols, because it’s a confusing limitation and there is a ton of overlap with default implementations. It would be far better to remove the feature.</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div style="white-space:pre-wrap" class=""><br class="">Optional protocols don't need to be expanded into Swift itself since I believe alternate methods and patterns exists to solve the same type of need.<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">Given that you don’t feel that optional requirements need to work in Swift-only protocols, and what I’ve said above about compatibility with Cocoa, do you still think we need to keep ‘@objc optional’ as a notion in the language?</div><div class=""><br class=""></div><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="white-space:pre-wrap" class=""><br class="">-Shawn</div><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Thu, Apr 7, 2016 at 5:12 PM Douglas Gregor via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="">Hi all,<div class=""><br class=""></div><div class="">Optional protocol requirements in Swift have the restriction that they only work in @objc protocols, a topic that’s come up a <a href="http://thread.gmane.org/gmane.comp.lang.swift.devel/1316/focus=8804" target="_blank" class="">number</a> of <a href="http://thread.gmane.org/gmane.comp.lang.swift.evolution/13347/focus=13480" target="_blank" class="">times</a>. The start of these threads imply that optional requirements should be available for all protocols in Swift. While this direction is implementable, each time this is discussed there is significant feedback that optional requirements are not a feature we want in Swift. They overlap almost completely with default implementations of protocol requirements, which is a more general feature, and people seem to feel that designs based around default implementations and refactoring of protocol hierarchies are overall better.</div><div class=""><br class=""></div><div class="">The main concern with removing optional requirements from Swift is their impact on Cocoa: Objective-C protocols, especially for delegates and data sources, make heavy use of optional requirements. Moreover, there are no default implementations for any of these optional requirements: each caller effectively checks for the presence of the method explicitly, and implements its own logic if the method isn’t there.</div><div class=""><br class=""></div><div class=""><b class="">A Non-Workable Solution: Import as optional property requirements</b></div><div class="">One suggestion that’s come up to map an optional requirement to a property with optional type, were “nil” indicates that the requirement was not satisfied. For example, </div><div class=""><br class=""></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">@protocol NSTableViewDelegate</font></div><div class=""><font face="Menlo" class="">@optional</font></div><div class=""><font face="Menlo" class="">- (nullable NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;</font></div><div class=""><font face="Menlo" class="">- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row;</font></div><div class=""><font face="Menlo" class="">@end</font></div></blockquote><div class=""><br class=""></div><div class="">currently comes in as</div><div class=""><br class=""></div><div class=""><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">@objc protocol NSTableViewDelegate {</font></div><div class=""><font face="Menlo" class=""> optional func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) -> NSView?</font></div><div class=""><font face="Menlo" class=""> optional func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div></blockquote></div><div class="">would come in as:</div><div class=""><br class=""></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">@objc protocol NSTableViewDelegate {</font></div><div class=""><font face="Menlo" class=""> var tableView: ((NSTableView, viewFor: NSTableColumn, row: Int) -> NSView?)? { get }</font></div><div class=""><font face="Menlo" class=""> var tableView: ((NSTableView, heightOfRow: Int) -> CGFloat)? { get }</font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">with a default implementation of “nil” for each. However, this isn’t practical for a number of reasons:</div><div class=""><br class=""></div><div class="">a) We would end up overloading the property name “tableView” a couple dozen times, which doesn’t actually work.</div><div class=""><br class=""></div><div class="">b) You can no longer refer to the member with a compound name, e.g., “delegate.tableView(_:viewFor:row:)” no longer works, because the name of the property is “tableView”.</div><div class=""><br class=""></div><div class="">c) Implementers of the protocol now need to provide a read-only property that returns a closure. So instead of</div><div class=""><br class=""></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">class MyDelegate : NSTableViewDelegate {</font></div><div class=""><font face="Menlo" class=""> func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) -> NSView? { … }</font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">one would have to write something like</div><div class=""><br class=""></div><div class=""><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">class MyDelegate : NSTableViewDelegate {</font></div><div class=""><font face="Menlo" class=""> var tableView: </font><span style="font-family:Menlo" class="">((NSTableView, viewFor: NSTableColumn, row: Int) -> NSView?)? = {</span></div><div class=""><span style="font-family:Menlo" class=""> </span><font face="Menlo" class="">… except you can’t refer to self in here unless you make it lazy ...</font></div><div class=""><span style="font-family:Menlo" class=""> }</span></div><div class=""><span style="font-family:Menlo" class="">}</span></div></blockquote></div><div class=""><br class=""></div><div class="">d) We’ve seriously considered eliminating argument labels on function types, because they’re a complexity in the type system that doesn’t serve much of a purpose.</div><div class=""><br class=""></div><div class="">One could perhaps work around (a), (b), and (d) by allowing compound (function-like) names like tableView(_:viewFor:row:) for properties, and work around (c) by allowing a method to satisfy the requirement for a read-only property, but at this point you’ve invented more language hacks than the existing @objc-only optional requirements. So, I don’t think there is a solution here.</div><div class=""><br class=""></div><div class=""><b class="">Proposed Solution: Caller-side default implementations</b></div><div class=""><br class=""></div><div class="">Default implementations and optional requirements differ most on the caller side. For example, let’s use NSTableView delegate as it’s imported today:</div><div class=""><br class=""></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">func useDelegate(delegate: NSTableViewDelegate) {</font></div><div class=""><font face="Menlo" class=""> if let getView = delegate.tableView(_:viewFor:row:) { // since the requirement is optional, a reference to the method produces a value of optional function type</font></div><div class=""><font face="Menlo" class=""> // I can call getView here</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class=""> if let getHeight = delegate.tableView(_:heightOfRow:) {</font></div><div class=""><font face="Menlo" class=""> // I can call getHeight here</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><span style="font-family:Menlo" class="">}</span></div></blockquote><div class=""><br class=""></div><div class="">With my proposal, we’d have some compiler-synthesized attribute (let’s call it @__caller_default_implementation) that gets places on Objective-C optional requirements when they get imported, e.g.,</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">@objc protocol NSTableViewDelegate {</font></div><div class=""><font face="Menlo" class=""> @__caller_default_implementation func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) -> NSView?</font></div><div class=""><font face="Menlo" class=""> </font><span style="font-family:Menlo" class="">@__caller_default_implementation</span><font face="Menlo" class=""> func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat</font></div><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class="">And “optional” disappears from the language. Now, there’s no optionality left, so our useDelegate example tries to just do correct calls:</div><div class=""><br class=""></div><div class=""><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">func useDelegate(delegate: NSTableViewDelegate) -> NSView? {</font></div><div class=""><font face="Menlo" class=""> let view = delegate.tableView(tableView, viewFor: column, row: row)</font></div><div class=""><font face="Menlo" class=""> let height = delegate.tableView(tableView, heightOfRow: row)</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div></blockquote></div><div class="">Of course, the code above will fail if the actual delegate doesn’t implement both methods. We need some kind of default implementation to fall back on in that case. I propose that the code above produce a compiler error on both lines *unless* there is a “default implementation” visible. So, to make the code above compile without error, one would have to add:</div><div class=""><br class=""></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">extension NSTableViewDelegate {</font></div><div class=""><font face="Menlo" class=""> @nonobjc func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) -> NSView? { return nil }</font></div><div class=""><font face="Menlo" class=""> </font></div><span style="font-family:Menlo" class=""> @nonobjc </span><span style="font-family:Menlo" class="">func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat { return 17 }</span><div class=""><font face="Menlo" class="">} </font></div></blockquote><div class=""><br class=""></div><div class="">Now, the useDelegate example compiles. If the actual delegate implements the optional requirement, we’ll use that implementation. Otherwise, the caller will use the default (Swift-only) implementation it sees. From an implementation standpoint, the compiler would effectively produce the following for the first of these calls:</div><div class=""><br class=""></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Menlo" class="">if delegate.responds(to: #selector(NSTableViewDelegate.tableView(_:viewFor:row:))) {</font></div><div class=""><font face="Menlo" class=""> // call the @objc instance method with the selector tableView:viewForTableColumn:row:</font></div><div class=""><font face="Menlo" class="">} else {</font></div><div class=""><font face="Menlo" class=""> // call the Swift-only implementation of tableView(_:viewFor:row:) in the protocol extension above</font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">There are a number of reasons why I like this approach:</div><div class=""><br class=""></div><div class="">1) It eliminates the notion of ‘optional’ requirements from the language. For classes that are adopting the NSTableViewDelegate protocol, it is as if these requirements had default implementations.</div><div class=""><br class=""></div><div class="">2) Only the callers to these requirements have to deal with the lack of default implementations. This was already the case for optional requirements, so it’s not an extra burden in principle, and it’s generally going to be easier to write one defaulted implementation than deal with it in several different places. Additionally, most of these callers are probably in the Cocoa frameworks, not application code, so the overall impact should be small.</div><div class=""><br class=""></div><div class="">Thoughts?</div><div class=""><br class=""></div><div class=""><span style="white-space:pre-wrap" class="">        </span>- Doug</div><div class=""><br class=""></div></div>_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div>
</div></blockquote></div><br class=""></div>_______________________________________________<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=""></div></blockquote></div><br class=""></div></body></html>