> On Apr 1, 2016, at 5:37 PM, Brent Royal-Gordon via swift-evolution 
> <swift-evolution@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.

Interesting point.

> 
> 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.

It’s “each" call site, not “the” call site. If there are multiple call sites, 
we’d presumably want to factor out the default behavior computation anyway.

> 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.

This is what concerns me most. Delegate protocols tend to grow large over time 
(for good reason), and having a large family of related protocols is hard to 
navigate.

        - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to