[swift-evolution] [Review] SE-0166: Swift Archival & Serialization

Tony Parker anthony.parker at apple.com
Mon Apr 10 17:13:47 CDT 2017


Hi Rex,

> On Apr 10, 2017, at 12:48 PM, Rex Fenley via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Forgive me if I'm missing something, this is a very large proposal and a lot to parse through. I like how everything is designed as far as I can tell except I'm not sure from this proposal how one would compose multiple different types of Decoders against the same output type. For example, with Location we have.
> 
> // Continuing examples from before; below is automatically generated by the compiler if no customization is needed.
> public struct Location : Codable {
> 	private enum CodingKeys : CodingKey {
>         case latitude
>         case longitude
>     }
> 
>     public init(from decoder: Decoder) throws {
>         let container = try decoder.container(keyedBy: CodingKeys.self)
>         latitude = try container.decode(Double.self, forKey: .latitude)
>         longitude = try container.decode(Double.self, forKey: .longitude)
>     }
> }
> 
> However, this initializer seems strictly tied to the `CodingKeys` set of coding keys. From what it appears, if this was used to decode from JSON the format would have to always be:
> 
> {
> 	"latitude" : 20.0
> 	"longitude" : 20.0
> }
> 
> I have a use case we're on my client we began the process of switching from one version of an API to another. In one version we had a payload similar to
> 
> {
> 	"user" : {
> 		"uuid" : "uuid string..."
> 		"can_send_message" : true
> 		"can_delete_message" : false
> 	}
> }
> 
> this would result in the following Codable (from "user") from what I'm following
> 
> public struct User : Codable {
> 	private enum CodingKeys : CodingKey {
>         case uuid
>         case can_send_message
>         case can_delete_message
>     }
> 
>     public init(from decoder: Decoder) throws {
>         let container = try decoder.container(keyedBy: CodingKeys.self)
>         uuid = try container.decode(Double.self, forKey: .uuid)
>         canSendMessage = try container.decode(Bool.self, forKey: .can_send_message)
>         canDeleteMessage = try container.decode(Bool.self, forKey: .can_delete_message)
>     }
> }
> 
> when we began switching over to the new api the payload was returned as
> 
> {
> 	user {
> 		"uuid" : "uuid string..."
> 		"permissions" : {
> 			"can_send_message" : true
> 			"can_delete_message" : false
> 		}
> 	}
> }
> 
> Here with "permissions" we have a new internal container with a separate set of coding keys. Issue is in my use case I still need to maintain a way to decode the old version simultaneously; we guard all new changes behind feature flags in case something goes awry and we need to roll back our changes.
> 
> How would one go about expressing this new Decoding and the previous Decoding simultaneously on the same User type?

You would fall out of the automatically-generated scenario here, but this use case is exactly what the ‘container’ API is for. You can create a container with a new set of keys, then decode from it.

Another approach would be to create a nested type that conforms with Codable which represents the “permissions” as a type of its own.

- Tony

> 
> 
> -- 
> Rex Fenley  |  IOS DEVELOPER
> 
> 
> Remind.com <https://www.remind.com/> |  BLOG <http://blog.remind.com/>  |  FOLLOW US <https://twitter.com/remindhq>  |  LIKE US <https://www.facebook.com/remindhq>_______________________________________________
> 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/20170410/3d2d0c18/attachment.html>


More information about the swift-evolution mailing list