[Update] Updates to SE-0166 and SE-0167


(Itai Ferber) #1

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of [SE-0166](https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md) and [SE-0167](https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md) (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

swift-archival-serialization-updates.html (62.1 KB)


(David Hart) #2

Sending out again to the whole mailing list :wink:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

···

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 and SE-0167 (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Pitiphong Phongpattranont) #3

Hi swift-evolution,

I have a few feedbacks on SE-0166 and SE-0167. I’m a library maintainer of a Swift library for my company. We’re a payment gateway service and have a wide range of support library in many programming languages (including Swift).

Here’re my feedbacks

1. The auto synthesized code from the Swift compiler is a great feature but I’m not sure if this is a bug. If I have a property of type Dictionary<String, Any>, the auto synthesize doesn’t work and I need to implement the init(from decoder:) method manually (with code like `metadata = try container.decodeIfPresent([String: Any].self, forKey: .metadata)`) I will report this as a bug on bugs.swift.org <http://bugs.swift.org/>
2. In JSONEncoder/Decoder, you can specify the date parsing behavior since there’re many ways to represent this. My thought is that that should apply to `DateComponents` too since there are also many ways to represent `DateComponent` e.g. the ISO8601 also has a spec for parsing the date or time which should map to `DateComponents` type in Swift. And since the DateComponents already conforms to the Decodable protocol so I cannot (and should not) override the system behavior so I need to do the decoding manually on every types that have a property of DateComponents type
3. Since Swift has an associated value enum while many others doesn’t have (including JavaScript which is the mother of JSON), I design our library to use the power of associated value enum as much as possible. This means that there are some types/properties those are built from a multiple properties of a JSON object.
For example: The status property of Charge is an enum which has a associated value case for `failure` status. So in my library it is built from the `status` and `failureMessage` properties in JSON. For now there is no simple or automatic way (auto synthesized code from Swift Compiler) to do this in Decodable. I need to implement it manually on every types those have this similar properties. And TBH I still don’t have any ideas on how to design the Decodable to support this feature.

Those are my feedbacks on SE-0166 and SE-0167 for now. I hope my feedbacks would help the Swift and Swift community

Best regards,
Pitiphong Phongpattranont

···

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback
about the outcome of
[SE-0166](https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md)
and
[SE-0167](https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md)
(both internally and externally), and we gathered a collection of
updates that we’re going to introduce to the proposals and to the
implementation.

Attached is rendered HTML (I don’t want to make your mail clients
unusable like last time!) that lays out what we’d like to do. We’re
not looking to do a full review of these changes, but if you have
feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented
(the new error types, some of the optionality changes, collection
conformances, etc.), but we are receptive to comments on all of it. The
existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai


(Itai Ferber) #4

Reply-all this time too. :slight_smile:
Thanks for the feedback, David!

encodeIfPresent and decodeIfPresent are not strictly necessary, but they’re useful for further cutting down boilerplate. encodeIfPresent is equivalent to

if let value = value {
    try container.encode(value, forKey: .someKey)
}
and decodeIfPresent is equivalent to

if container.contains(.someKey) {
    value = try container.decode(Value.self, forKey: .someKey)
} else {
    value = nil
}
They’re not big, but when you have a long list of optional properties, it’s much easier to read and comprehend than staring at a wall of Optional wrapping/unwrapping:

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    if container.contains(.prop1) {
        prop1 = try container.decode(Prop1Type.self, forKey: .prop1)
    } else {
        prop1 = nil
    }

    if container.contains(.prop2) {
        prop2 = try container.decode(Prop2Type.self, forKey: .prop2)
    } else {
        prop2 = nil
    }

    if container.contains(.prop3) {
        prop3 = try container.decode(Prop3Type.self, forKey: .prop3)
    } else {
        prop3 = nil
    }
}

// vs.

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    prop1 = try container.decodeIfPresent(Prop1Type.self, forKey: .prop1)
    prop2 = try container.decodeIfPresent(Prop2Type.self, forKey: .prop2)
    prop3 = try container.decodeIfPresent(Prop3Type.self, forKey: .prop3)
}

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

···

On 23 Jun 2017, at 13:52, David Hart wrote:

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

On Jun 24, 2017, at 1:29 AM, David Hart <david@hartbit.com> wrote:

Sending out again to the whole mailing list :wink:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Tony Parker) #5

Hi Pitiphong,

Hi swift-evolution,

I have a few feedbacks on SE-0166 and SE-0167. I’m a library maintainer of a Swift library for my company. We’re a payment gateway service and have a wide range of support library in many programming languages (including Swift).

Here’re my feedbacks

1. The auto synthesized code from the Swift compiler is a great feature but I’m not sure if this is a bug. If I have a property of type Dictionary<String, Any>, the auto synthesize doesn’t work and I need to implement the init(from decoder:) method manually (with code like `metadata = try container.decodeIfPresent([String: Any].self, forKey: .metadata)`) I will report this as a bug on bugs.swift.org <http://bugs.swift.org/>
2. In JSONEncoder/Decoder, you can specify the date parsing behavior since there’re many ways to represent this. My thought is that that should apply to `DateComponents` too since there are also many ways to represent `DateComponent` e.g. the ISO8601 also has a spec for parsing the date or time which should map to `DateComponents` type in Swift. And since the DateComponents already conforms to the Decodable protocol so I cannot (and should not) override the system behavior so I need to do the decoding manually on every types that have a property of DateComponents type

Would you be willing to share an example of what your JSON looks like and what your resulting DateComponents struct looks like here?

3. Since Swift has an associated value enum while many others doesn’t have (including JavaScript which is the mother of JSON), I design our library to use the power of associated value enum as much as possible. This means that there are some types/properties those are built from a multiple properties of a JSON object.

Yah, it’s certainly reasonable to adopt Decodable on an enum with an associated value, but I’m not sure if we should try to expand the automatic synthesis to handle this case or just ask these kinds of types to implement Decodable manually. We’re hoping that the synthesis covers a lot of cases, but it was a non-goal to attempt to cover 100% of the possible scenarios this way. We focused a lot on making the API usable on its own too.

- Tony

···

On Jul 13, 2017, at 12:37 AM, Pitiphong Phongpattranont via swift-evolution <swift-evolution@swift.org> wrote:

For example: The status property of Charge is an enum which has a associated value case for `failure` status. So in my library it is built from the `status` and `failureMessage` properties in JSON. For now there is no simple or automatic way (auto synthesized code from Swift Compiler) to do this in Decodable. I need to implement it manually on every types those have this similar properties. And TBH I still don’t have any ideas on how to design the Decodable to support this feature.

Those are my feedbacks on SE-0166 and SE-0167 for now. I hope my feedbacks would help the Swift and Swift community

Best regards,
Pitiphong Phongpattranont

> Hi swift-evolution,
>
> Over the course of the past few weeks, we’ve been gathering feedback
> about the outcome of
> [SE-0166](https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md)
> and
> [SE-0167](https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md)
> (both internally and externally), and we gathered a collection of
> updates that we’re going to introduce to the proposals and to the
> implementation.
>
> Attached is rendered HTML (I don’t want to make your mail clients
> unusable like last time!) that lays out what we’d like to do. We’re
> not looking to do a full review of these changes, but if you have
> feedback or questions, we’re happy to get responses here.
>
> Please note that some of these features have already been implemented
> (the new error types, some of the optionality changes, collection
> conformances, etc.), but we are receptive to comments on all of it. The
> existing proposals will also be updated to incorporate these updates.
>
> Thanks for all of your feedback!
>
> — Itai
>
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Pitiphong Phongpattranont) #6

Hi Tony,

Hi Pitiphong,

Hi swift-evolution,

I have a few feedbacks on SE-0166 and SE-0167. I’m a library maintainer of a Swift library for my company. We’re a payment gateway service and have a wide range of support library in many programming languages (including Swift).

Here’re my feedbacks

1. The auto synthesized code from the Swift compiler is a great feature but I’m not sure if this is a bug. If I have a property of type Dictionary<String, Any>, the auto synthesize doesn’t work and I need to implement the init(from decoder:) method manually (with code like `metadata = try container.decodeIfPresent([String: Any].self, forKey: .metadata)`) I will report this as a bug on bugs.swift.org <http://bugs.swift.org/>
2. In JSONEncoder/Decoder, you can specify the date parsing behavior since there’re many ways to represent this. My thought is that that should apply to `DateComponents` too since there are also many ways to represent `DateComponent` e.g. the ISO8601 also has a spec for parsing the date or time which should map to `DateComponents` type in Swift. And since the DateComponents already conforms to the Decodable protocol so I cannot (and should not) override the system behavior so I need to do the decoding manually on every types that have a property of DateComponents type

Would you be willing to share an example of what your JSON looks like and what your resulting DateComponents struct looks like here?

Sure, AFAIC ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601> support the date only string too and this is what my service is using for represent the date (that not include time) for example “2017-07-13” represents the date of July 13th, 2017 in Gregorian calendar.
The current behavior of JSONEncoder is encode each of the DateComponents properties into their owns keys in the JSON not using the ISO 8601. I think the way that the design of date encoding/decoding of JSONEncoder with `dateEncodingStrategy` property would also fit into this too.

The example of my JSON data is

{
  "object": "schedule",
  "id": "schd_test_584zfswqzu5m40sycxc",
  "start_date": "2017-05-30",
  "end_date": "2018-05-20",
  "next_occurrence_dates": [
    "2017-07-16",
    "2017-08-01",
    "2017-08-16",
  ],
  "created": "2017-05-30T08:37:10Z”
}

Note that the created property is `Date Time (Date)` The start_date and end_date are Date (DateComponents) and next_occurrence_dates is an array of Date (Array<DateComponents>).

3. Since Swift has an associated value enum while many others doesn’t have (including JavaScript which is the mother of JSON), I design our library to use the power of associated value enum as much as possible. This means that there are some types/properties those are built from a multiple properties of a JSON object.

Yah, it’s certainly reasonable to adopt Decodable on an enum with an associated value, but I’m not sure if we should try to expand the automatic synthesis to handle this case or just ask these kinds of types to implement Decodable manually. We’re hoping that the synthesis covers a lot of cases, but it was a non-goal to attempt to cover 100% of the possible scenarios this way. We focused a lot on making the API usable on its own too.

I understand your point. I also agree with you. That’s just my wish list for Swift feature but it must not out weight other perspective of design and implementation.

Also I find some interesting approach for this and I want to ask you for your opinion. For now I don’t make those enum to adopt Decodable protocol since those need to be built from the multiple key value pairs from the JSON. I decided to extract the raw value in `init(from decoder:)` and build the value manually.

But I saw someone post some code snippet by making those enum to adopt Decodable protocol and extracts the necessary key values pairs But they decode the enum by calling

`status = try ChargeStatus(from: decoder)`

For me personally, the adopting Decodable protocol part is great but the code to decode looks fishy to me.

Do you have any opinion on this approach?

Thank you
Pitiphong P.

···

On Jul 13, 2560 BE, at 23:20, Tony Parker <anthony.parker@apple.com> wrote:

On Jul 13, 2017, at 12:37 AM, Pitiphong Phongpattranont via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

- Tony

For example: The status property of Charge is an enum which has a associated value case for `failure` status. So in my library it is built from the `status` and `failureMessage` properties in JSON. For now there is no simple or automatic way (auto synthesized code from Swift Compiler) to do this in Decodable. I need to implement it manually on every types those have this similar properties. And TBH I still don’t have any ideas on how to design the Decodable to support this feature.

Those are my feedbacks on SE-0166 and SE-0167 for now. I hope my feedbacks would help the Swift and Swift community

Best regards,
Pitiphong Phongpattranont

> Hi swift-evolution,
>
> Over the course of the past few weeks, we’ve been gathering feedback
> about the outcome of
> [SE-0166](https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md)
> and
> [SE-0167](https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md)
> (both internally and externally), and we gathered a collection of
> updates that we’re going to introduce to the proposals and to the
> implementation.
>
> Attached is rendered HTML (I don’t want to make your mail clients
> unusable like last time!) that lays out what we’d like to do. We’re
> not looking to do a full review of these changes, but if you have
> feedback or questions, we’re happy to get responses here.
>
> Please note that some of these features have already been implemented
> (the new error types, some of the optionality changes, collection
> conformances, etc.), but we are receptive to comments on all of it. The
> existing proposals will also be updated to incorporate these updates.
>
> Thanks for all of your feedback!
>
> — Itai
>
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Hart) #7

What I still have difficulties understanding is what will be the semantic difference between decodeIfPresent and decode with optional type:

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    prop1 = try container.decodeIfPresent(Prop1Type.self, forKey: .prop1)
    prop2 = try container.decode(Optional<Prop2Type>.self, forKey: .prop2)
}

···

On 26 Jun 2017, at 19:10, Itai Ferber <iferber@apple.com> wrote:

Reply-all this time too. :slight_smile:
Thanks for the feedback, David!

encodeIfPresent and decodeIfPresent are not strictly necessary, but they’re useful for further cutting down boilerplate. encodeIfPresent is equivalent to

if let value = value {
    try container.encode(value, forKey: .someKey)
}
and decodeIfPresent is equivalent to

if container.contains(.someKey) {
    value = try container.decode(Value.self, forKey: .someKey)
} else {
    value = nil
}
They’re not big, but when you have a long list of optional properties, it’s much easier to read and comprehend than staring at a wall of Optional wrapping/unwrapping:

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    if container.contains(.prop1) {
        prop1 = try container.decode(Prop1Type.self, forKey: .prop1)
    } else {
        prop1 = nil
    }

    if container.contains(.prop2) {
        prop2 = try container.decode(Prop2Type.self, forKey: .prop2)
    } else {
        prop2 = nil
    }

    if container.contains(.prop3) {
        prop3 = try container.decode(Prop3Type.self, forKey: .prop3)
    } else {
        prop3 = nil
    }
}

// vs.

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    prop1 = try container.decodeIfPresent(Prop1Type.self, forKey: .prop1)
    prop2 = try container.decodeIfPresent(Prop2Type.self, forKey: .prop2)
    prop3 = try container.decodeIfPresent(Prop3Type.self, forKey: .prop3)
}
On 23 Jun 2017, at 13:52, David Hart wrote:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

On Jun 24, 2017, at 1:29 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

Sending out again to the whole mailing list :wink:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Itai Ferber) #8

Taking your code as an example:
Swift

Swift
struct Foo : Codable {
    var prop1: Int?
    var prop2: Int?
    
    enum CodingKeys { ... }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        prop1 = try container.decodeIfPresent(Int.self, forKey: .prop1)
        prop2 = try container.decode(Int?.self, forKey: .prop2)
    }
    
    func encode(to encoder: Encoder) throws { ... }
}

try decoder.decode(Foo.self, from: "{ \"prop1\": 42, \"prop2\": 99 }".data(using: .utf8)!)
// => prop1 == Optional(42), prop2 == Optional(99)

try decoder.decode(Foo.self, from: "{ \"prop1\": null, \"prop2\": 99 }".data(using: .utf8)!)
// => prop1 == nil, prop2 == Optional(99)

try decoder.decode(Foo.self, from: "{ \"prop1\": 42, \"prop2\": null }".data(using: .utf8)!)
// => prop1 == Optional(42), prop2 == nil

try decoder.decode(Foo.self, from: "{ \"prop2\": 99 }".data(using: .utf8)!)
// => prop1 == nil, prop2 == Optional(99)

try decoder.decode(Foo.self, from: "{ \"prop1\": 42 }".data(using: .utf8)!)
// => error, .keyNotFound (key "prop2" is missing)

decode<T>(_:forKey:) always expects the key to be there; if T == Optional<U> then the value may be null, but the entry must be present, since that’s what you’re asserting.
decodeIfPresent<T>(_:forKey:) will return nil if the key is not present, or if T == Optional<U> and the value is null.

(This, BTW, is not a change in semantics from how things work today.)

···

On Jun 26, 2017, at 1:03 PM, David Hart <david@hartbit.com> wrote:

What I still have difficulties understanding is what will be the semantic difference between decodeIfPresent and decode with optional type:

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    prop1 = try container.decodeIfPresent(Prop1Type.self, forKey: .prop1)
    prop2 = try container.decode(Optional<Prop2Type>.self, forKey: .prop2)
}

On 26 Jun 2017, at 19:10, Itai Ferber <iferber@apple.com <mailto:iferber@apple.com>> wrote:

Reply-all this time too. :slight_smile:
Thanks for the feedback, David!

encodeIfPresent and decodeIfPresent are not strictly necessary, but they’re useful for further cutting down boilerplate. encodeIfPresent is equivalent to

if let value = value {
    try container.encode(value, forKey: .someKey)
}
and decodeIfPresent is equivalent to

if container.contains(.someKey) {
    value = try container.decode(Value.self, forKey: .someKey)
} else {
    value = nil
}
They’re not big, but when you have a long list of optional properties, it’s much easier to read and comprehend than staring at a wall of Optional wrapping/unwrapping:

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    if container.contains(.prop1) {
        prop1 = try container.decode(Prop1Type.self, forKey: .prop1)
    } else {
        prop1 = nil
    }

    if container.contains(.prop2) {
        prop2 = try container.decode(Prop2Type.self, forKey: .prop2)
    } else {
        prop2 = nil
    }

    if container.contains(.prop3) {
        prop3 = try container.decode(Prop3Type.self, forKey: .prop3)
    } else {
        prop3 = nil
    }
}

// vs.

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    prop1 = try container.decodeIfPresent(Prop1Type.self, forKey: .prop1)
    prop2 = try container.decodeIfPresent(Prop2Type.self, forKey: .prop2)
    prop3 = try container.decodeIfPresent(Prop3Type.self, forKey: .prop3)
}
On 23 Jun 2017, at 13:52, David Hart wrote:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

On Jun 24, 2017, at 1:29 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

Sending out again to the whole mailing list :wink:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Hart) #9

Great! Just wanted to make sure I understood :slight_smile:

···

On 26 Jun 2017, at 22:36, Itai Ferber <iferber@apple.com> wrote:

Taking your code as an example:
Swift

Swift
struct Foo : Codable {
    var prop1: Int?
    var prop2: Int?
    
    enum CodingKeys { ... }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        prop1 = try container.decodeIfPresent(Int.self, forKey: .prop1)
        prop2 = try container.decode(Int?.self, forKey: .prop2)
    }
    
    func encode(to encoder: Encoder) throws { ... }
}

try decoder.decode(Foo.self, from: "{ \"prop1\": 42, \"prop2\": 99 }".data(using: .utf8)!)
// => prop1 == Optional(42), prop2 == Optional(99)

try decoder.decode(Foo.self, from: "{ \"prop1\": null, \"prop2\": 99 }".data(using: .utf8)!)
// => prop1 == nil, prop2 == Optional(99)

try decoder.decode(Foo.self, from: "{ \"prop1\": 42, \"prop2\": null }".data(using: .utf8)!)
// => prop1 == Optional(42), prop2 == nil

try decoder.decode(Foo.self, from: "{ \"prop2\": 99 }".data(using: .utf8)!)
// => prop1 == nil, prop2 == Optional(99)

try decoder.decode(Foo.self, from: "{ \"prop1\": 42 }".data(using: .utf8)!)
// => error, .keyNotFound (key "prop2" is missing)

decode<T>(_:forKey:) always expects the key to be there; if T == Optional<U> then the value may be null, but the entry must be present, since that’s what you’re asserting.
decodeIfPresent<T>(_:forKey:) will return nil if the key is not present, or if T == Optional<U> and the value is null.

(This, BTW, is not a change in semantics from how things work today.)

On Jun 26, 2017, at 1:03 PM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

What I still have difficulties understanding is what will be the semantic difference between decodeIfPresent and decode with optional type:

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    prop1 = try container.decodeIfPresent(Prop1Type.self, forKey: .prop1)
    prop2 = try container.decode(Optional<Prop2Type>.self, forKey: .prop2)
}

On 26 Jun 2017, at 19:10, Itai Ferber <iferber@apple.com <mailto:iferber@apple.com>> wrote:

Reply-all this time too. :slight_smile:
Thanks for the feedback, David!

encodeIfPresent and decodeIfPresent are not strictly necessary, but they’re useful for further cutting down boilerplate. encodeIfPresent is equivalent to

if let value = value {
    try container.encode(value, forKey: .someKey)
}
and decodeIfPresent is equivalent to

if container.contains(.someKey) {
    value = try container.decode(Value.self, forKey: .someKey)
} else {
    value = nil
}
They’re not big, but when you have a long list of optional properties, it’s much easier to read and comprehend than staring at a wall of Optional wrapping/unwrapping:

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    if container.contains(.prop1) {
        prop1 = try container.decode(Prop1Type.self, forKey: .prop1)
    } else {
        prop1 = nil
    }

    if container.contains(.prop2) {
        prop2 = try container.decode(Prop2Type.self, forKey: .prop2)
    } else {
        prop2 = nil
    }

    if container.contains(.prop3) {
        prop3 = try container.decode(Prop3Type.self, forKey: .prop3)
    } else {
        prop3 = nil
    }
}

// vs.

func init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    prop1 = try container.decodeIfPresent(Prop1Type.self, forKey: .prop1)
    prop2 = try container.decodeIfPresent(Prop2Type.self, forKey: .prop2)
    prop3 = try container.decodeIfPresent(Prop3Type.self, forKey: .prop3)
}
On 23 Jun 2017, at 13:52, David Hart wrote:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

On Jun 24, 2017, at 1:29 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

Sending out again to the whole mailing list :wink:

There are a lot of great changes here which make sense after the fact. I'll try to play around with them.

One thing I'm concerned about: with the new Optional conformance, why do we still need decodeIfPresent and encodeIfPresent? They seem superfluous now, and potentially confusing. Should users call encodeIfPresent/decodeIfPresent or encode/decode with an optional type? Do the have the same semantics?

On 23 Jun 2017, at 21:47, Itai Ferber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi swift-evolution,

Over the course of the past few weeks, we’ve been gathering feedback about the outcome of SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md> and SE-0167 <https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md> (both internally and externally), and we gathered a collection of updates that we’re going to introduce to the proposals and to the implementation.

Attached is rendered HTML (I don’t want to make your mail clients unusable like last time!) that lays out what we’d like to do. We’re not looking to do a full review of these changes, but if you have feedback or questions, we’re happy to get responses here.

Please note that some of these features have already been implemented (the new error types, some of the optionality changes, collection conformances, etc.), but we are receptive to comments on all of it. The existing proposals will also be updated to incorporate these updates.

Thanks for all of your feedback!

— Itai

<swift-archival-serialization-updates.html>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution