<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 Apr 7, 2016, at 6:12 PM, Douglas Gregor via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div></blockquote><snip><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><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></div></blockquote><div><br class=""></div>If I understand correctly:</div><div><br class=""></div><div>1. Optional methods in protocols imported from objective C gain a special flag when imported as Swift methods</div><div>2. Such methods can be unimplemented (such that the message will fail, or responds(to:) returns false) in objective-c code and bridged swift instances.</div><div>3. To implement that protocol in swift, you must have implementations of every protocol method, including optional ones</div><div>4. This means that there may be manual work around bridging protocols with optional messages into swift.</div><div>5. If the method implementation is marked @nonobjc it will fulfill the swift requirement that there be a method implementation, but that implementation will not be exposed to Objective-C</div><div>6. Swift code can call such a @nonobjc implementation, while Objective-C code will consider there to be nothing there.</div><div>7 An implementation that is only be applied to the swift variant is possibly fine in extensions while generates a warning within a swift class, or perhaps requires an explicit @nonobjc attribute.</div><div><br class=""></div><div>I like it, except for the requirement for a manual implementation in Swift before you can support the protocol. </div><div><br class=""></div><div>I looked at whether the protocol members might be implemented by returning the nil/zero/false value you would get if you sent the message to nil. </div><div><br class=""></div><div>Cursory search quickly hit NSAccessibilityElement, which has an optional “accessibilityIdentifier” method returning a non-nil NSString. I suspect that the method also requires the string to be non-empty. Thus, a default implementation that represents the right thing to represent in a generated default implementation would likely be brittle.</div><div><br class=""></div><div>I could also see an imported protocol where *any* default implementation of the optional method would not meet the requirements of an actual implementation of the method (not being versed in this particular interface, I’ll just straw man that the identifier is required to be unique within an application)</div><div><br class=""></div><div>Thus I wonder if there may be some other way to support the idea of two distinct protocols, the protocol as defined in Objective C, and the protocol as defined in Swift.</div><div><br class=""></div><div>Options that sprang to mind:</div><div>- the methods which return optional values have a default implementation that returns nil. Methods which return non-optional values will have the Swift protocol modified to return an Optional value, which they will do by default. So for example, Still on NSAccessibilityElement,</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>-<span style="font-family: Menlo; font-size: 11px;" class="">(BOOL)isAccessibilityFocused</span></div><div><br class=""></div><div>would be imported as</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>func isAccessibilityFocused() -> Bool?</div><div><br class=""></div><div>with a default implementation returning nil. To actually implement the objective C protocol’s optional method, you must implement the version with the correct nullability variant, so in this case:</div><div><br class=""></div><div> @objc func isAccessiblityFocused() -> Bool { return focused }</div><div><br class=""></div><div>(Of course, this means that a non-optional result value would need to satisfy an optional result valued variant in a protocol)</div><div><br class=""></div><div>- similar to the above, but rather than overriding result values to support a default variant, overload ErrorType. Imported variants which throw will by default throw a bridging-specific ErrorType when called from Swift. Optional methods which do not throw will have a throwing variant generated on the Swift side. </div><div><br class=""></div><div>Again similar to the above, to satisfy the objective-C protocol requirement your implementation would need to be non-throwing.</div><div><br class=""></div><div>I like this better in terms of capturing to the best of ones ability the ‘spirit’ of optional methods and behavior in swift. However, this seems like it will result in more deviation between the Swift and Objective-C protocol method signatures.</div><div><br class=""></div><div>Comments?</div><div><br class=""></div><div>-DW</div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><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 class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div class=""><br class=""></div></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=""></body></html>