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

Reply via email to