Interesting proposal, but I wanted to mention a couple of potential issues off the top of my head. I know when I was using optional requirements in Objective C, I would often use the presence/lack of the method (not just whether it returned nil) in the logic of my program. I used the presence of a method as a way for the implementor of a delegate to naturally communicate whether they wanted a more advanced feature. The absence of the method itself is information which can be utilized, not just whether it returns nil, and I believe that is part of what people are asking for when they say they want optional methods in Swift.
Let me try to give a simplified example which I am not sure how you would work around in this proposal: Let’s say there is a datasource protocol which optionally asks for an image associated with a particular piece of data (imagine a table or collection view type custom control). If the method is not implemented in the data source, then a different view is shown for each data point that doesn’t have a place for images at all. If the method is implemented, but returns nil, then a default image is used as a placeholder instead (in a view which has a place for images). tl;dr: Optional methods are often used as customization points, and the methods, if implemented, may also have another meaning/use for nil. Similarly, a different back-end implementation may be used in the case where an optional method is not implemented. Let’s say you have something like a tableview with an optional method giving rowHeights. If that method is unimplemented, it is possible to have a much more efficient layout algorithm… and in some cases, you may check for the existence of the optional method when the delegate is set, and swap out a different layout object based on which customizations are needed (and again nil might mean that a height/etc... should be automatically calculated). This is the ability I miss the most. Not saying the proposal is unworkable, just wanted to add some food for thought. I know I really miss optional methods in Swift. In some areas Swift is a lot more powerful, but there are lots of things I used to do in Obj C that I haven’t figured out how to do in Swift yet (if they are even possible). I am kind of disturbed by the trend/desire to get rid of the smalltalk-ness, as opposed to finding new and safer ways to support that flexibility/expressiveness. I would really like to see swift deliver on it’s promise of being a more modern alternative to ObjC (which it isn’t yet, IMHO) instead of just a more modern alternative to C++/Java. Thanks, Jon > Proposed Solution: Caller-side default implementations > > Default implementations and optional requirements differ most on the caller > side. For example, let’s use NSTableView delegate as it’s imported today: > > func useDelegate(delegate: NSTableViewDelegate) { > if let getView = delegate.tableView(_:viewFor:row:) { // since the > requirement is optional, a reference to the method produces a value of > optional function type > // I can call getView here > } > > if let getHeight = delegate.tableView(_:heightOfRow:) { > // I can call getHeight here > } > } > > 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., > > @objc protocol NSTableViewDelegate { > @__caller_default_implementation func tableView(_: NSTableView, viewFor: > NSTableColumn, row: Int) -> NSView? > @__caller_default_implementation func tableView(_: NSTableView, > heightOfRow: Int) -> CGFloat > } > > And “optional” disappears from the language. Now, there’s no optionality > left, so our useDelegate example tries to just do correct calls: > > func useDelegate(delegate: NSTableViewDelegate) -> NSView? { > let view = delegate.tableView(tableView, viewFor: column, row: row) > let height = delegate.tableView(tableView, heightOfRow: row) > } > > 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: > > extension NSTableViewDelegate { > @nonobjc func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) > -> NSView? { return nil } > > @nonobjc func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat { > return 17 } > } > > 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: > > if delegate.responds(to: > #selector(NSTableViewDelegate.tableView(_:viewFor:row:))) { > // call the @objc instance method with the selector > tableView:viewForTableColumn:row: > } else { > // call the Swift-only implementation of tableView(_:viewFor:row:) in the > protocol extension above > } > > There are a number of reasons why I like this approach: > > 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. > > 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. > > Thoughts? > > - Doug
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution