[swift-evolution] [Draft] open and public protocols
Xiaodi Wu
xiaodi.wu at gmail.com
Sun Feb 19 17:40:41 CST 2017
On Sun, Feb 19, 2017 at 5:15 PM, Brent Royal-Gordon via swift-evolution <
swift-evolution at swift.org> wrote:
> > On Feb 18, 2017, at 10:58 PM, David Waite via swift-evolution <
> swift-evolution at swift.org> wrote:
> >
> > I am unsure if this feature is a good idea. Does someone have a
> real-world use for this which isn’t just hiding strong implementation
> coupling behind a protocol?
>
> Strong coupling is sometimes inevitable.
>
> In a previous thread, I brought up an example of a place I would use this
> feature: Wrapping the SQLite APIs. For instance:
>
> public protocol SQLiteValue {
> init(statement: SQLiteStatement, columnAt index: Int)
> throws
> func bind(to statement: SQLiteStatement, at index: Int)
> throws
> }
> extension Int: SQLiteValue {
> public init(statement: SQLiteStatement, columnAt index:
> Int) throws {
> self = sqlite3_column_int(statement.stmt, index)
> }
> public func bind(to statement: SQLiteStatement, at index:
> Int) throws {
> try throwIfNotOK(
> sqlite3_bind_int64(statement.stmt, index,
> self)
> )
> }
> }
> extension Double: SQLiteValue {…}
> extension Data: SQLiteValue {…}
> extension String: SQLiteValue {…}
> extension Optional: SQLiteValue where Wrapped: SQLiteValue {…}
>
> This is a case of your hated "strong implementation coupling". But the
> coupling is to a library that ultimately writes data to disk in a portable
> format. Strong coupling here is inevitable.
>
> What is the purpose of permitting outside conformances to `SQLiteValue`?
Suppose you released this library and I used it for my SQLite needs. But my
application uses Float behind the scenes, which can be losslessly promoted
(as you must know) as Double. For convenience of interfacing with your
library, I conform Float to SQLiteValue. Likewise, let's say I implement a
new Rational type (not actually hypothetical, hehe), and I decide that I
want to store that as Double (it'd be precise enough once all the
calculations are done). For convenience, I conform Rational<Int> to
SQLiteValue. I could make good on these conformances by having `init()` and
`bind(to:at:)` do a numeric cast and then forward to the relevant methods
on Double. Now, I understand why your library wouldn't do this, since
willy-nilly conversions between types are worth at least careful thought,
but as a non-library client that uses Float pervasively, I'd have good
justification for that extension.
There is no useful way to conform to `SQLiteValue`; the underlying library
> supports certain types, and I've implemented support for those types.
> Allowing outside conformances can only mislead people into fruitlessly
> trying to conform their types, not realizing that the calls they need
> simply aren't exposed.
>
What is the harm of permitting an outside conformance to `SQLiteValue`?
> Moreover, exposing these details unnecessarily freezes the design of
> `SQLiteValue`. If I want to change the design of this parameter handling in
> a future version, well, too bad, the API is public, I'm stuck. *For an API
> I don't intend anyone to conform to publicly in the first place.* That kind
> of sucks, doesn't it?
>
But with `public` vs `open`, your API is still frozen whichever you choose.
Even if you can't conform to `SQLiteValue`, there is no guarantee that your
clients won't _invoke_ `SQLiteValue.bind(to:at:)`, so you can't redesign
the protocol anyway. What other flexibility are you looking for?
>
> --
> 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/20170219/53ac643d/attachment.html>
More information about the swift-evolution
mailing list