> On 31 May 2017, at 14:36, Gwendal Roué via swift-evolution 
> <[email protected]> wrote:
> 
> Itai,
> 
> (This email is not technical)
> 
> I'm not claiming that SE-0166 should be able to address all archival formats. 
> I've been talking about GRDB to show at least one format that SE-0166 doesn't 
> cover well. And should SE-0166 be fixed to support SQL (in the GRDB fashion), 
> this does not mean that other developers won't eventually fight with SE-0166 
> until they understand it does not fit their bill.
> 
> But there's something very special with SE-0166:
> 
> It's in the standard library, with all the backward-compatibility constraints 
> that come with such a position.
> 
> IT'S BLESSED WITH CODE GENERATION.

One important future goal I hope we can address in future versions of Swift is 
powerful macro/meta-programming features. I think like Sourcery 
(https://github.com/krzysztofzablocki/Sourcery 
<https://github.com/krzysztofzablocki/Sourcery>) but at compile-time, in the 
language. Once we have that, I hope we can re-implement SE-0166’s code 
generation using those meta-programming features into the Standard Library and 
tear it out of the compiler. If we can achieve that, we will have a strong 
toolbox for any third-library which have similar needs.

PS: With meta-programming, we could also re-implement the automatic 
Equatable/Hashable conformances. More magic in the compiler is usually a bad 
thing I think.

> I don't know if you, Michael LeHew, Tony Parker, and the core team, realize 
> the importance of this insanely great privilege granted to this proposal.
> 
> The lack of introspection and macros in Swift makes SE-0166 immensely 
> attractive for a whole category of libraries.
> 
> When SE-0166 is lacking, should those libs ignore it, and lose CODE 
> GENERATION, which means looking like it's still Swift 3?
> 
> Should those libs claim SE-0166 conformance, and raise runtime errors for 
> invalid inputs (where "invalid" does not mean "invalid data", or "invalid 
> code", but "impossible to fit in SE-0166" <=> "invalid library")?
> 
> I'd like to hear a little better than that :-) GRDB is a library of unusual 
> quality (sorry for the auto-congratulation). Until now, fatal errors thrown 
> by GRDB were always a sign of programmer mistake. Not of defects in the 
> foundations. I wish this would remain true.
> 
> Less caveats and runtime/fatal errors mean less user frustration.
> 
> Less caveats also mean less documentation to write. Ideally, this should be 
> enough: https://github.com/groue/GRDB.swift/tree/Swift4#codable-records 
> <https://github.com/groue/GRDB.swift/tree/Swift4#codable-records>
> 
> Gwendal
> Just a guy that write Swift apps and libraries
> 
> 
>> Le 30 mai 2017 à 20:49, Itai Ferber <[email protected] 
>> <mailto:[email protected]>> a écrit :
>> 
>> Hi Gwendal,
>> 
>> There are no stupid questions — everything helps hammer out this API, so I 
>> appreciate you taking the time to look at this so deeply.
>> I have to confess that I’m not familiar with this concept, but let’s take a 
>> look:
>> 
>> if let valueType = T.self as? DatabaseValueConvertible.Type {
>>     // if column is missing, trigger the "missing key" error or return nil.
>> } else if let complexType = T.self as? RowConvertible.Type {
>>     // if row scope is missing, trigger the "missing key" error or return 
>> nil.
>> } else {
>>     // don't know what to do
>>     fatalError("unsupported")
>> }
>> Is it appropriate for a type which is neither DatabaseValueConvertible nor 
>> RowConvertible to be decoded with your decoder? If not, then this warrants a 
>> preconditionFailure or an error of some sort, right? In this case, that 
>> would be valid.
>> 
>> You also mention that "it’s still impossible to support other Codable types" 
>> — what do you mean by this? Perhaps there’s a way to accomplish what you’re 
>> looking to do.
>> In any case, one option (which is not recommended unless if there are other 
>> avenues to solve this by) is to perform a "dry run" decoding. Attempt to 
>> decode the type with a dummy decoder to see what container it will need, 
>> then prepare your approach and do it again for real. Obviously, this isn’t a 
>> clean way to do it if we can find alternatives, but it’s an option.
>> 
>> — Itai
>> 
>> On 29 May 2017, at 4:51, Gwendal Roué via swift-evolution wrote:
>> 
>> Hello,
>> 
>> I have already asked stupid questions about SE-0167 and SE-0166, but this 
>> time I hope this is a real one.
>> 
>> According so SE-0166, codable types themselves instantiate a single value 
>> decoder, or a keyed container:
>> 
>> public struct Farm : Codable {
>> public init(from decoder: Decoder) throws {
>> let container = try decoder.container(keyedBy: CodingKeys.self
>> ...
>> }
>> }
>> 
>> public enum Animal : Int, Codable {
>> public init(from decoder: Decoder) throws
>> let intValue = try decoder.singleValueContainer().decode(Int.self)
>> ...
>> }
>> }
>> 
>> According to SE-0167, decoder decode non-trivial types in their 
>> decode(_:forKey:) and decodeIfPresent(_:forKey:) methods:
>> 
>> func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : 
>> Decodable
>> func decodeIfPresent<T>(_ type: T.Type, forKey key: Key) throws -> T? where 
>> T : Decodable
>> 
>> My trouble is that the decoder does not know whether the Decodable type will 
>> ask for a keyed container, or for a single value container.
>> 
>> Why is it a problem?
>> 
>> In the context of decoding of SQL rows, keys may refer to different things, 
>> depending on whether we are decoding a *value*, or a *complex object*:
>> 
>> - for values, keys are column names, as everybody can expect
>> - for complex objects, keys are names of "row scopes". Row scopes are a 
>> concept introduced by GRDB.swift and allows a type that knows how to consume 
>> `SELECT * FROM table1` to consume as well the results of `SELECT table1.*, 
>> table2.* FROM table1 JOIN table2` through a "scope" that presents the row in 
>> the shape expected by the consumer (here, only columns from table1).
>> 
>> This is supposed to allow support for types that contain both nested types 
>> and values (one of the goals of SE-0166 and SE-0167):
>> 
>> struct Compound : Codable {
>> let someStruct: SomeStruct // object that feeds on the "someStruct" scope
>> let name: String // value that feeds on the "name" column
>> }
>> 
>> The two decoding methods decode(_:forKey:) and decodeIfPresent(_:forKey:) 
>> can't be implemented nicely, because they don't know whether the decodable 
>> type will ask for a keyed container or a single value container, and thus 
>> they don't know whether they should look for the presence of a row scope, or 
>> of a column:
>> 
>> A workaround is to perform runtime checks on the GRDB protocols adopted by 
>> T, as below. But it's still impossible to support other codable types:
>> 
>> if let valueType = T.self as? DatabaseValueConvertible.Type {
>> // if column is missing, trigger the "missing key" error or return nil.
>> } else if let complexType = T.self as? RowConvertible.Type {
>> // if row scope is missing, trigger the "missing key" error or return nil.
>> } else {
>> // don't know what to do
>> fatalError("unsupported")
>> }
>> 
>> Do you have any advice?
>> 
>> Gwendal Roué
>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> 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

Reply via email to