[swift-evolution] [Accepted] SE-0166: Swift Archival & Serialization
Itai Ferber
iferber at apple.com
Mon May 1 14:04:57 CDT 2017
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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170501/241aba30/attachment.html>
More information about the swift-evolution
mailing list