[swift-evolution] [Draft] open and public protocols

David Hart david at hartbit.com
Sun Feb 19 17:36:46 CST 2017


It’s funny. My favourites SQLite library actually does it as I suggested :)

https://github.com/groue/GRDB.swift/blob/master/GRDB/Core/DatabaseValue.swift

> On 20 Feb 2017, at 00:34, David Hart <david at hartbit.com> wrote:
> 
>> 
>> On 20 Feb 2017, at 00:15, 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 {…}
> 
> That problem is that I don’t think the API should be written this way. This cries for the use of enums instead:
> 
> enum SQLiteValue {
>    case int(Int)
>    case double(Double)
>    case data(Data)
>    case string(String)
> }
> 
> protocol SQLiteValueConvertible {
>    var sqliteValue: SQLiteValue { get }
> }
> 
> extension Int : SQLiteValueConvertible {
>    var sqliteValue: SQLiteValue { return .int(self) }
> }
> 
> And that API actually allows interesting extension points. For example, how about automatic binding of dates:
> 
> extension Date : SQLiteValueConvertible {
>    var sqliteValue: SQLiteValue { return .double(timeIntervalSince1970) }
> }
> 
> I keep getting the impression that the uses for the proposals are actually cases where an enum is required.
> 
>> 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`? 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.
>> 
>> 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?
>> 
>> -- 
>> 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/20170220/cc0ba663/attachment.html>


More information about the swift-evolution mailing list