> On Apr 1, 2016, at 7:37 PM, Brent Royal-Gordon via swift-evolution
> <[email protected]> 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…
I’d actually go a bit further: for at least *some* of the uses of optional
protocol methods, default implementations are necessary but not sufficient; to
really “Swift-ify” without *losing* functionality you also would need to do a
much-more-involved redesign of the protocol methods.
As just one example, I *think* the following API sketch is *adequate* for a
Swift-ified` `tableView:heightForRowAtIndexPath:`:
/// Mocked-up, "Swifty" table-view-delegate protocol:
protocol TableViewDelegate : class {
/// Non-optional method, returning a "policy" enum that e.g. provides enough
/// information to the table view to let it choose the appropriate layout
strategy...
func rowHeightPolicyForTableView(tableView: TableView) ->
TableViewRowHeightPolicy
}
/// “How to calculate height” information for an entire table view.
enum TableViewRowHeightPolicy {
/// all rows have identical height, table-view can operate in the "fast"
/// mode, like setting `tableView.rowHeight = $someHeight` w/o delegate.
case Uniform(CGFloat)
/// table view should use auto-layout to measure each cell automatically;
/// like `tableView.rowHeight = UITableViewAutomaticDimension` w/o delegate.
case Automatic
/// get per-row height info from `RowHeightCalculator`; equivalent to your
/// having a delegate that implements `tableView:heightForRowAtIndexPath:`.
case Manual(RowHeightCalculator)
}
/// A dedicated “row-height-calculator” protocol. On the one hand, this could
/// also be "just a closure", but promoting it into a protocol seems more
/// future-proof (e.g. if additional calculation-options become supported
later).
///
/// Unfortunately, making this an object means having to think harder than
/// before about ownership issues; this seems mildly thorny.
protocol RowHeightCalculator : class {
/// Returns the height-information for the given row; to *fully* recapture
/// existing `UITableView` functionality we need to return more than
`CGFloat`.
func heightForRow(in tableView: UITableView, at indexPath: NSIndexPath) ->
RowHeight
}
/// Height-calculation result for a single row.
enum RowHeight {
/// Tells the table view to use auto-layout to measure this row's cell;
/// equivalent to *returning* `UITableViewAutomaticDimension`.
case Automatic
/// Tells the table view to use the specified height for this row.
case Height(CGFloat)
}
…and at least AIUI that’s a complete representation of the various
row-height-related behaviors it’s possible arrive-at, today, via various
combinations of “did you implement `tableView:heightForRowAtIndexPath:` or
not?” and/or “are you setting/returning `UITableViewAutomaticDimension`?.
Note also that this is just the behavior for row-heights; to fully-cover
today’s user-exposed functionality, you’d need to handle header-heights and
footer-heights (which have similar methods/semantics), and probably also the
estimated-height methods for rows, headers, and footers.
Pausing here for a moment, I think the above illustrates why the topic keeps
coming up: although it’s certainly *possible* to get to the same place w/out
optional protocol methods, it sometimes takes a bit of a design rethink to get
there. The API surface also seems to get quite a bit larger; I think it’s fair
to classify this as simply “making already-present complexity
actually-visible”, but it’d still be bit of a shift.
For the actual `tableView:heightForRowAtIndexPath:` family I’m not sure what I
think; I personally like a more-explicit approach as per the above, but once
you start to include the header-and-footer heights and also the estimated
height APIs, it gets to be a bit much; more so when you think about how this
API looks with similar approaches for other currently-optional method “suites"
(like highlight/selection management “suite", the menu/action “suite”, etc.).
To conclude, in many cases "optional methods => methods w/ reasonable default
implementation” is all you need, but in *some* cases you would also need to
design your API very differently to have equivalent functionality.
I assume patterns and idioms for such designs will evolve over time, but at
present there’s not a lot of Swift-ified datasource/delegate-style APIs out
there to use for inspiration.
> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution