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 <da...@hartbit.com> wrote:
> 
>> 
>> On 20 Feb 2017, at 00:15, Brent Royal-Gordon via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>>> On Feb 18, 2017, at 10:58 PM, David Waite via swift-evolution 
>>> <swift-evolution@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@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution

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

Reply via email to