Thank you Brent for your effort. I will try this way.

By the way I thought that the protocol conformance with conditions were already 
retained/adopted in Swift 4. You seem to say that it was postponed. It’s too 
bad in my opinion. But thanks again for the info.

> On 18 Oct 2017, at 23:38, Brent Royal-Gordon <br...@architechies.com> wrote:
> 
>> On Oct 17, 2017, at 10:00 AM, Thierry Passeron via swift-users 
>> <swift-users@swift.org> wrote:
>> 
>> Hi everyone,
>> 
>> In the process of familiarising myself with Encodable/Decodable protocols I 
>> was trying to apply it to the Range struct in order to persist a Range in 
>> CoreData records. However, I seem to hit the wall with it and keep getting 
>> errors. This happens in the Xcode 9.0.1 playground, not sure which swift 
>> version is used if it’s 4 or 3.x but anyways, I get “Ambiguous reference to 
>> member ‘encode(_:forKey:)’ on every encode/decode method calls.
>> 
>> extension Range {
>> enum CodingKeys : String, CodingKey {
>>   case upperBound
>>   case lowerBound
>> }
>> }
>> 
>> extension Range: Codable {
>> 
>> public func encode(to encoder: Encoder) throws {
>>   var container = encoder.container(keyedBy: CodingKeys.self)
>>   try container.encode(upperBound, forKey: .upperBound)
>>   try container.encode(lowerBound, forKey: .lowerBound)
>> }
>> 
>> public init(from decoder: Decoder) throws {
>>   let values = try decoder.container(keyedBy: CodingKeys.self)
>>   self.upperBound = try values.decode(Bound.self, forKey: .upperBound)
>>   self.lowerBound = try values.decode(Bound.self, forKey: .lowerBound)
>> }
>> 
>> }
>> 
>> How would one add Codable support to such a struct? I’m feeling it may 
>> require a bit of “where” clauses in extension because of the Generic aspect 
>> of this struct but I fail to make the compiler happy.
> 
> What you'd *like* to be able to do is say that a Range is codable only when 
> its bounds are also codable:
> 
>       extension Range: Codable where Bound: Codable {
>               …
>       }
> 
> But this isn't currently supported in Swift. (The compiler team is working on 
> it right now, and it'll probably be here in Swift 5, if not in 4.1.) So for 
> the time being, you have to fake it dynamically. Unless you want to use 
> private APIs, the easiest way is probably to use a dictionary:
> 
>       extension Range: Decodable /* where Bound: Decodable */ {
>               public init(from decoder: Decoder) throws {
>                       let dict = try [String: Bound](from: decoder)
>                       
>                       guard let lower = 
> dict[CodingKey.lowerBound.stringValue] else {
>                               throw DecodingError.valueNotFound(Bound.self, 
> .init(codingPath: decoder.codingPath + [CodingKey.lowerBound], 
> debugDescription: "lowerBound not found")
>                       }
>                       guard let lower = 
> dict[CodingKey.upperBound.stringValue] else {
>                               throw DecodingError.valueNotFound(Bound.self, 
> .init(codingPath: decoder.codingPath + [CodingKey.upperBound], 
> debugDescription: "upperBound not found")
>                       }
>                       
>                       self.init(uncheckedBounds: (lower: lower, upper: upper))
>               }
>       }
> 
>       extension Range: Encodable /* where Bound: Encodable */ {
>               public func encode(to encoder: Encoder) throws {
>                       try [CodingKey.lowerBound.stringValue: lowerBound, 
> CodingKey.upperBound.stringValue: upperBound].encode(to: encoder)
>               }
>       }
> 
> This should mimic the structure you'll eventually be able to generate with a 
> keyed container; when Swift becomes able to do this properly, you can update 
> the code to encode and decode directly.
> 
> Hope this helps,
> -- 
> Brent Royal-Gordon
> Architechies

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

Reply via email to