[swift-evolution] [Accepted] SE-0166: Swift Archival & Serialization
Itai Ferber
iferber at apple.com
Mon May 1 14:06:49 CDT 2017
Sorry, one clarifying statement: it's not the JSON encoder and decoder
that will be providing this renaming (since they should be encoding the
key values they are given as-is); the key names are part of the
definition of the enum, as declared as part of the type.
On 1 May 2017, at 12:04, Itai Ferber via swift-evolution wrote:
> Yes, this should be true for most types.
> The compiler derives conformance based on a nested `CodingKeys` type
> within your `Codable` type. If you do not supply one, it will derive
> one on your behalf, but if you do provide one, making a naming
> transition like this is trivial:
>
> ```swift
> public struct Post : Codable {
> let authorID: Int
> let authorName: String
> let bodyText: String
>
> private enum CodingKeys: String, CodingKey {
> case authorID = "author_id"
> case authorName = "author_name"
> case bodyText = "body_text"
> }
>
> // init(from:) and encode(to:) are still automatically generated
> }
> ```
>
> This is something we wanted to explicitly support as we don't want
> users to have to violate Swift naming guidelines, and is a step along
> the progressive disclosure of the API that we want to provide.
> As long as the case names of the enum match 1-to-1 with property
> names, derived conformance still applies.
>
> On 1 May 2017, at 11:39, Anders Ha wrote:
>
>> I thought it would be quite trivial to have the JSON encoder and
>> decoder transforming the keys between camel case and snake case,
>> wouldn't it?
>>
>>
>> Regards
>> Anders
>>
>>
>>> On 2 May 2017, at 1:57 AM, Jon Shier via swift-evolution
>>> <swift-evolution at swift.org> wrote:
>>>
>>> FYI, I’d give the derived implementations a very low chance of
>>> ever being used for JSON. Unless developers violate the Swift naming
>>> guidelines for their properties at least or they don’t have
>>> properties with multiword keys.
>>> Once this functionality has landed for the Swift 4 branch, I plan
>>> to implement some of the tricky JSON types I had to decode on a
>>> recent project, just to see how painful the custom syntax will be,
>>> and to compare it to my existing Argo implementation. Hopefully
>>> there will be time for at least one round of feedback to be
>>> integrated into this functionality.
>>>
>>>
>>>
>>> Jon
>>>
>>>
>>>> On May 1, 2017, at 12:54 PM, Itai Ferber via swift-evolution
>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>>>> wrote:
>>>>
>>>> Hi Goffredo,
>>>>
>>>>> On Apr 26, 2017, at 2:00 PM, Goffredo Marocchi <panajev at gmail.com
>>>>> <mailto:panajev at gmail.com>> wrote:
>>>>>
>>>>> Hello Itai,
>>>>>
>>>>> Sorry for the confusion, but I understood that the following
>>>>>
>>>>>> To answer your second question, the reason is that using the
>>>>>> protocol implies that all encoders and decoders must support
>>>>>> anything that conforms to that protocol. We’re not sure this is
>>>>>> a reasonable requirement. Many formats do not have any kind of
>>>>>> support for arbitrary size integers, for example. Therefore, we
>>>>>> felt it was best to limit it to a set of concrete types.
>>>>>
>>>>> meant it would actually hinder that kind of transformation or make
>>>>> it more difficult to write custom decoders and encoders. Sorry if
>>>>> I misunderstood that.
>>>>>
>>>>> One follow up question: what would happen if inside the JSON mock
>>>>> object you posted I were to remove the 'address' key (in terms of
>>>>> the produced object and how to access its inner properties)?
>>>>>
>>>>> What would happen if I remove the 'name' one or better if I add
>>>>> another key to the JSON object?
>>>> Codable conformance is derived by default to require that all
>>>> non-optional properties be initialized. This means that if you have
>>>> a non-optional property address: Address but there is no address
>>>> key in the JSON payload you're decoding from, it will throw an
>>>> error to indicate that the key was not found.
>>>> On the flip side, if the JSON payload has information in it which
>>>> your type does not have (e.g. if there is an address in the JSON,
>>>> but your Person just has name), the extra data is ignored.
>>>>
>>>> This, however, is just in the default, derived conformance. For
>>>> more complex cases, you can always provide your own init(from:) and
>>>> encode(to:)to do custom decoding. If you have a property which may
>>>> or may not be in the JSON, you can always decodeIfPresent, which
>>>> will return nil if the key or value was not found.
>>>> If you need to access sub-objects in the JSON data which do not map
>>>> to your properties 1-to-1, e.g. your payload looks like {"name":
>>>> "John Doe", "address": { "street": "1 Infinite Loop", ... } }, but
>>>> your type looks like
>>>> struct Person {
>>>> let name: String
>>>> let street: String
>>>> let city: String
>>>> // ...
>>>> }
>>>> then you can always access the nested data by requesting a
>>>> nestedContainer(keyedBy: ..., forKey: .address) which will return a
>>>> container wrapping the address sub-object, which you can then pull
>>>> fields out of.
>>>>
>>>> The derived conformance case gives a reasonable default, but you
>>>> can always write your own init(from:) and encode(to:) to handle
>>>> custom needs.
>>>>
>>>>>
>>>>> Sent from my iPhone
>>>>>
>>>>> On 26 Apr 2017, at 21:28, Itai Ferber <iferber at apple.com
>>>>> <mailto:iferber at apple.com>> wrote:
>>>>>
>>>>>> Hi Goffredo,
>>>>>>
>>>>>> Unless I'm misunderstanding what you mean here, this is exactly
>>>>>> what we're proposing with the API — anything Encodable can
>>>>>> encode any type that is Encodable as a nested value:
>>>>>>
>>>>>> struct Person : Codable {
>>>>>> let name: String
>>>>>> let address: Address
>>>>>> }
>>>>>>
>>>>>> struct Address : Codable {
>>>>>> let street: String
>>>>>> let city: String
>>>>>> let state: String
>>>>>> let zipCode: Int
>>>>>> let country: String
>>>>>> }
>>>>>>
>>>>>> let address = Address(street: "1 Infinite Loop", city:
>>>>>> "Cupertino", state: "CA", zipCode: 95014, country: "United
>>>>>> States")
>>>>>> let person = Person(name: "John Doe", address: address)
>>>>>>
>>>>>> let encoder = JSONEncoder()
>>>>>> let payload = try encoder.encode(person)
>>>>>> print(String(data: payload, encoding: .utf8)!) // => {"name":
>>>>>> "John Doe", address: {"street": "1 Infinite Loop", ... } }
>>>>>>
>>>>>> let decoder = JSONDecoder()
>>>>>> let decoded = try decoder.decode(Person.self, from: payload) //
>>>>>> => Person(name: "John Doe", address: ...)
>>>>>> Or have I misunderstood you?
>>>>>>
>>>>>> — Itai
>>>>>>
>>>>>> On 26 Apr 2017, at 13:11, Goffredo Marocchi via swift-evolution
>>>>>> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Sent from my iPhone
>>>>>>
>>>>>> On 26 Apr 2017, at 17:24, Tony Parker via swift-evolution
>>>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>>>>>> wrote:
>>>>>>
>>>>>>> Hi Riley,
>>>>>>>
>>>>>>>> On Apr 25, 2017, at 6:11 PM, Riley Testut via swift-evolution
>>>>>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>> I’m sure this has already been discussed, but why are the
>>>>>>>> methods throwing NSErrors and not Enums? If I’m remembering
>>>>>>>> correctly, the original reason for this was because this was
>>>>>>>> meant to be a part of Foundation. Now that this is in the
>>>>>>>> Standard Library, however, it seems strange that we’re still
>>>>>>>> using NSError.
>>>>>>>>
>>>>>>>> Second question that again I’m sure was asked and answered
>>>>>>>> already, but: why do we require implementations for each
>>>>>>>> concrete numeric type (Int, Int8, Int16, Float, etc), instead
>>>>>>>> of using protocols (such as the new Integer protocols)?
>>>>>>>
>>>>>>> To answer your second question, the reason is that using the
>>>>>>> protocol implies that all encoders and decoders must support
>>>>>>> anything that conforms to that protocol.
>>>>>>
>>>>>> Would this make it easier to transform nested JSON into a nested
>>>>>> object/struct? If so it could be useful, very useful.
>>>>>>
>>>>>>> We’re not sure this is a reasonable requirement. Many formats
>>>>>>> do not have any kind of support for arbitrary size integers, for
>>>>>>> example. Therefore, we felt it was best to limit it to a set of
>>>>>>> concrete types.
>>>>>>>
>>>>>>
>>>>>> I honk we would be missing a trick, unless I am missing something
>>>>>> here, that was very powerful in libraries like Mantle for iOS:
>>>>>> the ability to translate a nested JSON object (some keys in the
>>>>>> JSON object having a JSON object as value, etc...) in an MTLModel
>>>>>> subclass composed of other MTLModel subclasses where doing the
>>>>>> transformation of the root object would call the right model
>>>>>> needed to transform for the child JSON objects.
>>>>>> Working with Mantle is safe, rugged (it does not cause crashes if
>>>>>> the JSON file changes), and allows you to break the problem into
>>>>>> chunks and present a coherent simple view to the code that makes
>>>>>> use of the instance you created out of the JSON input. Reference:
>>>>>> https://github.com/Mantle/Mantle/blob/master/README.md
>>>>>> <https://github.com/Mantle/Mantle/blob/master/README.md>
>>>>>>
>>>>>>
>>>>>>> We could change our minds on this before we ship Swift 4, if we
>>>>>>> feel it was the wrong decision. Now that the proposals are
>>>>>>> accepted we will be landing these branches in master soon, which
>>>>>>> means everyone has a great chance to try it out and see how it
>>>>>>> feels in real world usage before it’s final.
>>>>>>>
>>>>>>> - Tony
>>>>>>>
>>>>>>>>
>>>>>>>>> On Apr 25, 2017, at 3:59 PM, Douglas Gregor via
>>>>>>>>> swift-evolution <swift-evolution at swift.org
>>>>>>>>> <mailto:swift-evolution at swift.org>> wrote:
>>>>>>>>>
>>>>>>>>> Proposal Link:
>>>>>>>>> https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md
>>>>>>>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md>
>>>>>>>>>
>>>>>>>>> Hello Swift Community,
>>>>>>>>>
>>>>>>>>> The review of SE-0166 “Swift Archival & Serialization” ran
>>>>>>>>> from April 6...12, 2017. The proposal is accepted with some
>>>>>>>>> minor modifications. Specifically, the core protocols and
>>>>>>>>> types will be sunk down into the Swift standard library for
>>>>>>>>> more tight integration with the Swift language and compiler,
>>>>>>>>> and the operations specifically involving Foundation’s
>>>>>>>>> “Data” type will be removed. The proposal document has
>>>>>>>>> been updated with more detail. Thank you everyone for
>>>>>>>>> participating in this review!
>>>>>>>>>
>>>>>>>>> - Doug
>>>>>>>>> Review Manager
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> swift-evolution mailing list
>>>>>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> swift-evolution mailing list
>>>>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> 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/20170501/0de299a5/attachment.html>
More information about the swift-evolution
mailing list