[swift-evolution] Modify optional method semantics for swift

Matthew Johnson matthew at anandabits.com
Mon May 9 17:28:47 CDT 2016


> On May 9, 2016, at 5:13 PM, Rod Brown via swift-evolution <swift-evolution at swift.org> wrote:
> 
> This issue I see here, and one that people seem to often forget in discussions on Swift a Evolution, is that optional methods aren't just used to change a default value. Their existence often actually changes behavior completely.
> 
> Take for example UITableViewDelegate and its method "tableView:heightForRowAtIndexPath:".
> 
> If you implement this method, every cell can have a variable height, and the table cannot optimize for it, so the math, storage and management of the data is specific to every row. This method will be called for every cell in the table view at load, because the table must calculate that size to compute the content size.
> 
> If you do not implement this method, the cell sizing is simple. Table view doesn't have to call this method again and again, but not only that: it can actually optimise the layout with the knowledge that there is no variable sizing. That makes the mathematics of content size so much easier to compute, and results in a far better performing table view, down to even working at 60fps on an original iPhone.
> 
> UITableView has optimized the variable sizing problems recently with estimated values that allow the table to "estimate" the sizing, and then adjust appropriately its details as the cells load. This also how self-sizing cells work. That said, it's an avoidance to deal with the limitations that the method creates: if it exists on the delegate, you're opting into a much slower and less efficient sizing path.
> 
> The problem then becomes how do we model such optimizations in Swift. Default methods, while useful for plenty of cases, don't work with this system as there is no runtime check to see if the object actually implements that method. The optimizations don't just check the existence for a default value - they actually lead to different code paths.
> 
> Can this be done? Absolutely. Either by segregating the protocols as you mentioned, or by adding some other way to cue the optimized sizing path. That said, it's certainly not as clean as the Objective-C design.

Clean is in the eye of the beholder.  I definitely don’t think the Objective-C design feels right in Swift.  

There have been times where I implemented delegates where the row height strategy was decided at initialization time.  In Objective-C I was able to do this by implementing respondsToSelector.  That feels a bit dirty, but it works.  In pure Swift there is no way to do that at all.  

Swift allows a delegate protocol design to take a position on whether the initialization-time decision is supported or is a code smell that should be disallowed.  The approach of segregated protocols disallows it.  Alternative mechanisms such as a boolean getter allow for it.

> 
> In general, I think default implementations fix a lot of the simpler cases surrounding optional methods and actually simplify other implementations (no runtime checks!). But they don't solve the real value proposition that the fully dynamic Objective-C design provided in this feature.
> 
> Do I support default implementations on protocols as a concept? Definitely. But I don't think we should kid ourselves that this solves anything apart from the simpler cases.

I agree with this.  I think we should study the more complex cases and establish guidelines around idiomatic patterns for them in Swift.  This may even result in proposals for language enhancements to support the idioms we want to see in Swift.  But I’m glad to see “optional requirements” going away.

-Matthew

> 
> - Rod
> 
> On 10 May 2016, at 2:15 AM, Carlos Rodríguez Domínguez via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote: 
> 
>> Rationale:
>> 
>> As a everybody knows, “optional” keyword is present in swift solely to maintain compatibility with objective-c protocols. Optional methods in protocols are neither a swift capability, nor a wanted one. In fact, proposal [0070] intends to begin the transition to an optionals-free language. In fact, optionals, as presented by objective-c, are a manner to avoid interface segregation.
>> 
>> Nonetheless, in many occasions, optionals are used to model customized behavior vs default one. For instance, if you take a look at the documentation of UITableViewDataSource or delegate, you’ll see that optional methods are not required, since the framework provides a default behavior that can be customized by implementing the corresponding optional methods.
>> 
>> Consequently, is most cases, optional methods in objective-c are a means to replace the semantics of default protocol method implementations, as supported through extensions in swift.
>> 
>> Therefore, my proposal is to modify the semantics of “optional” keyword in swift to mean: “you must provide a default implementation of this method through an extension”. This is different from objective-c semantics, which mean “the implementation of this method may not be provided”.
>> 
>> Detailed design:
>> 
>> In this proposal, protocols could be defined like this:
>> 
>> protocol Datasource {
>> 	associatedtype Element
>> 
>> 	var count:Int {get}
>> 	func elementAt(index:Int) -> Element
>> 	optional func color(elementIndex:Int) -> UIColor
>> }
>> 
>> However, this definition enforces the developer to create an extension a provide a default implementation of the optional method:
>> 
>> extension Datasource {
>> 	func color(elementIndex:Int) -> UIColor {
>> 		return UIColor.blackColor()
>> 	}
>> }
>> 
>> In this way, what we are achieving is that we are avoiding objective-c optional semantics (which is a way to avoid interface segregation), but we are making explicit that a method in a protocol requires a default implementation, thus not requiring the developer to re-implement the method in any entity adopting the protocol (as it currently happens when we provide a default method implementation). Moreover, we are making explicit that a certain protocol method has a default implementation, which can be confusing right now.
>> 
>> Note that in this proposal, the intention is to keep both "@objc optional” and simply “optional” keywords, to highlight both semantics. However, in order to avoid @objc optional semantics as much as possible (to be able to remove it in a future swift release), new annotations could be incorporated to optional methods in objective-c code, to specify the default returned value. For instance, the annotations could be like this:
>> 
>> @protocol Datasource
>> 	-(NSInteger) numberOfElements;
>> 	-(NSObject*) elementAtIndex:(NSInteger)index;
>> 
>> 	@optional
>> 	-(UIColor*) colorOfElementAtIndex:(NSInteger)index __attribute__((swift_default_value(“UIColor.blackColor()")));
>> @end
>> 
>> Note that this annotation also allows to better understand the default behavior in case the method is not implemented without reading the documentation. This annotation should produce a swift code similar to the above one.
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160509/f0010128/attachment.html>


More information about the swift-evolution mailing list