[swift-evolution] [Proposal] Make optional protocol methods first class citizens

T.J. Usiyan griotspeak at gmail.com
Fri Apr 1 19:55:23 CDT 2016


-1
I hope that default implementations living in the protocol will address
this. I would even prefer to move in 'the other direction' and have
optional methods on protocols come into swift as default implementations.
TJ

On Sat, Apr 2, 2016 at 6:07 AM, Brent Royal-Gordon via swift-evolution <
swift-evolution at swift.org> wrote:

> > Protocol requirements with default (no-op) implementations already
> satisfy that design goal, no?
>
> Kind of. If I may steelman* optional members for a moment...
>
> In cases where a default implementation would do, the default
> implementation will usually also be the behavior you want for a nil
> instance, but there's no convenient way to share logic between the two. For
> example, consider this:
>
>         protocol UITableViewDelegate {
>                 ...
>                 func tableView(_ tableView: UITableView,
> heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
>         }
>         extension UITableViewDelegate {
>                 func tableView(_ tableView: UITableView,
> heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
>                         return tableView.rowHeight
>                 }
>         }
>
>         class UITableView {
>                 ...
>                 private func addRow(at indexPath: NSIndexPath) {
>                         ...
>                         cell.size.height = delegate?.tableView(self,
> heightForRowAtIndexPath: indexPath) ?? rowHeight
>                         ...
>                 }
>                 ...
>
> You have to duplicate the default logic both in the default implementation
> and at the call site, but there is no convenient way to share it—the
> extension method can't call into an expression at some call site, and
> contrarily the call site can't invoke the default logic from the extension.
>
> If the method were optional, then optional chaining would solve this
> problem for us:
>
>         protocol UITableViewDelegate {
>                 ...
>                 optional func tableView(_ tableView: UITableView,
> heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
>         }
>
>         class UITableView {
>                 ...
>                 private func addRow(at indexPath: NSIndexPath) {
>                         ...
>                         cell.size.height = delegate?.tableView?(self,
> heightForRowAtIndexPath: indexPath) ?? rowHeight
>                         ...
>                 }
>                 ...
>
> This way, there is only one source of default behavior: the call site.
>
> I'm also concerned by the thought of just how many sub-protocols we might
> end up with. When I try to fully factor NSTableViewDelegate (as it
> currently exists in the headers), I end up with ten protocols:
>
>         NSTableViewDelegate
>                 - tableView:willDisplayCell:forTableColumn:row:
>
>         NSTableViewLayoutDelegate: NSTableViewDelegate
>                 - tableView:heightOfRow:
>
>         NSTableViewRowSelectionDelegate: NSTableViewDelegate
>                 - tableView:shouldSelectRow:
>                 - selectionShouldChangeInTableView:
>                 - tableViewSelectionIsChanging:
>                 - tableViewSelectionDidChange:
>                 - tableView:shouldTrackCell:forTableColumn:row: (10.5)
>                 - tableView:selectionIndexesForProposedSelection: (10.5)
>
>         NSTableViewTypeSelectDelegate: NSTableViewDelegate (10.5)
>                 - tableView:typeSelectStringForTableColumn:row:
>                 - tableView:nextTypeSelectMatchFromRow:toRow:forString:
>                 -
> tableView:shouldTypeSelectForEvent:withCurrentSearchString:
>
>         NSTableViewToolTipDelegate: NSTableViewDelegate
>                 -
> tableView:toolTipForCell:rect:tableColumn:row:mouseLocation:
>
>         NSTableViewColumnDelegate: NSTableViewDelegate
>                 - tableView:shouldEditTableColumn:row:
>                 - tableView:shouldSelectTableColumn:
>                 - tableView:mouseDownInHeaderOfTableColumn:
>                 - tableView:didClickTableColumn:
>                 - tableView:didDragTableColumn:
>                 - tableViewColumnDidMove:
>                 - tableViewColumnDidResize:
>                 - tableView:sizeToFitWidthOfColumn: (10.6)
>                 - tableView:shouldReorderColumn:toColumn: (10.6)
>
>         NSTableViewCellExpansionDelegate: NSTableViewDelegate (10.5)
>                 - tableView:shouldShowCellExpansionForTableColumn:row:
>
>         NSTableViewCustomCellDelegate: NSTableViewDelegate (10.5)
>                 - tableView:dataCellForTableColumn:row:
>                 - tableView:isGroupRow:
>
>         NSTableViewCellViewDelegate: NSTableViewDelegate (10.7)
>                 - tableView:viewForTableColumn:row:
>
>         NSTableViewRowViewDelegate: NSTableViewDelegate (10.7)
>                 - tableView:rowViewForRow:
>                 - tableView:didAddRowView:forRow:
>                 - tableView:didRemoveRowView:forRow:
>                 - tableView:rowActionsForRow:edge: (10.11)
>
> Some of these are probably unnecessary; they could be merged into
> NSTableViewDelegate and given default implementations. But at least a few
> of them would be very much needed. Would users be able to navigate this
> mess? Would they discover the features tucked away in sub-protocols? I'm
> just not sure.
>
> And of course the safety issues that make optional protocol members
> dangerous in Objective-C don't exist in Swift. Swift will force you to test
> for the presence of an optional member; you can't carelessly call one.
>
> (Incidentally, resilience might also benefit from supporting optional
> protocol members and adding a `public(optional)` feature which made all
> call sites outside the resilience domain treat all members as optional. You
> could then mark protocols meant to be called only by clients inside the
> resilience domain—like data sources and delegates—with `public(optional)`
> and gain the ability to delete obsolete members.)
>
>
>
> * Steelmanning is the opposite of strawmanning.
>
> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> 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/20160402/eb37e291/attachment.html>


More information about the swift-evolution mailing list