Adding type conversion capabilities to JSON encode/decode

Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
        "name": "Endeavor”,
        "abv": 8.9,
        "brewery": "Saint Arnold”,
        "style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
    let name: String
    let abv: Convertible<String>
    let brewery: String
    let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

Hi Brandon,

Thanks for looking at this! We’ve got plans internally to potentially add a strategy to `JSONEncoder`/`JSONDecoder` to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of `JSONDecoder` while not requiring any special annotations on `Codable` types.

— Itai

···

On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:

Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
        "name": "Endeavor”,
        "abv": 8.9,
        "brewery": "Saint Arnold”,
        "style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
    let name: String
    let abv: Convertible<String>
    let brewery: String
    let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

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

One downside I see is that the encoder wouldn't know if this specific field
was originally a number instead of a string. If the same Codable struct is
used for GET and POST, for example, the post-encode JSON string could be
invalid because the server expects a number instead of a string for that
field.

An explicit mapping of JSON value type to Codable ivar type would be
needed, but this can create validation issues because while all numbers can
be converted to strings (decode is OK), not all strings can be converted to
numbers (encode is not OK).

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

            <swift-corelibs-dev@swift.org>

···

From: "Sneed, Brandon via swift-corelibs-dev"
To: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Date: 08/30/2017 01:00 PM
Subject: [swift-corelibs-dev] Adding type conversion capabilities to
            JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org

Hi everyone,

Just throwing this out to see if anyone else is working on this, or has
opinions/suggestions on how it’s implemented. I’d like to add this to the
Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
        "name": "Endeavor”,
        "abv": 8.9,
        "brewery": "Saint Arnold”,
        "style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d
like to make it such that I can let the system know it’s ok to convert it
from a number to a string as opposed to throwing an exception. The
benefits are:

1. It’s defensive; service types can change without causing my
application to crash.
2. It allows a developer to work with the types they want to work
with as opposed to what the server provides, thus saving them time of
writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug,
make them fix it”, which is valid but the reality is we’re not all in
control of the services we injest. The same type of logic could be applied
to a member name changing, though I haven’t seen this happen often in
practice. I do see types in a json payload change with some frequency
though. I think much of the reason stems from the fact that type
conversion in javascript is effectively free, ie: you ask for a String, you
get a String if possible.

To implement this type conversion in practice, looking at it from the point
of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear
and relatively unambiguous. The downside is it’s unknown which member is
likely to get converted. And since it’s opt-in, conversion doesn’t happen
if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
    let name: String
    let abv: Convertible<String>
    let brewery: String
    let style: BeerStyle
}

This seems tedious for developers, but would show which types are being
converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this
conversion behavior was the default and no end-developer changes required.
I think that could be done without impact to code that’s been already been
written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have
to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=utPJ8lPG7RUnVBM2S83fXgDyBRVtivz1iTkYslFYIKI&s=JYMXmKeoK1ETGzoGDIMdIL6M1MNEo8ij571lOudNSWw&e=

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

···

From: <iferber@apple.com> on behalf of Itai Ferber <iferber@apple.com>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,

Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.

— Itai

On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:

Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{

        "name": "Endeavor”,

        "abv": 8.9,

        "brewery": "Saint Arnold”,

        "style": "ipa"

}

and a struct defined as:

struct Beer: Codable {

    let name: String

    let abv: String

    let brewery: String

    let style: BeerStyle

}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.

2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {

    let name: String

    let abv: String

    let brewery: String

    let style: BeerStyle

}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {

    let name: String

    let abv: Convertible<String>

    let brewery: String

    let style: BeerStyle

}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.swift.org%2Fmailman%2Flistinfo%2Fswift-corelibs-dev&data=02|01|brsneed%40ebay.com|0e58a975be44418826d608d4efd427dc|46326bff992841a0baca17c16c94ea99|0|0|636397141865218008&sdata=ytYIqDtMesw4NnpUbFmiWF2%2FKfxlawG4YuVWPJd099Y%3D&reserved=0&gt;

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony

···

On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com> on behalf of Itai Ferber <iferber@apple.com>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,

Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.

— Itai

On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:

Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
        "name": "Endeavor”,
        "abv": 8.9,
        "brewery": "Saint Arnold”,
        "style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
    let name: String
    let abv: Convertible<String>
    let brewery: String
    let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.swift.org%2Fmailman%2Flistinfo%2Fswift-corelibs-dev&data=02|01|brsneed%40ebay.com|0e58a975be44418826d608d4efd427dc|46326bff992841a0baca17c16c94ea99|0|0|636397141865218008&sdata=ytYIqDtMesw4NnpUbFmiWF2%2FKfxlawG4YuVWPJd099Y%3D&reserved=0&gt;\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My own json encode/decode library worked this way and it was really great, however in trying to leverage Swift4 into it, or to replace it, I just don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance. The only way I can think of to accomplish that is to create *another* type, JSONString for example, but since String is a struct, I can’t subclass it, and instead need to have the real value buried inside of it … it seems to start getting messy very quickly. It also adds the obfuscation of dealing with yet another type, which I’m not against, but just feels less than ideal.

Brandon Sneed

···

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Itai Ferber <iferber@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony

On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com<mailto:iferber@apple.com>> on behalf of Itai Ferber <iferber@apple.com<mailto:iferber@apple.com>>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,
Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.
— Itai
On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
        "name": "Endeavor”,
        "abv": 8.9,
        "brewery": "Saint Arnold”,
        "style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
    let name: String
    let abv: String
    let brewery: String
    let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
    let name: String
    let abv: Convertible<String>
    let brewery: String
    let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.swift.org%2Fmailman%2Flistinfo%2Fswift-corelibs-dev&data=02|01|brsneed%40ebay.com|0e58a975be44418826d608d4efd427dc|46326bff992841a0baca17c16c94ea99|0|0|636397141865218008&sdata=ytYIqDtMesw4NnpUbFmiWF2%2FKfxlawG4YuVWPJd099Y%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.swift.org%2Fmailman%2Flistinfo%2Fswift-corelibs-dev&data=02|01|brsneed%40ebay.com|f2eba37a5b40474e09b108d4efd5372d|46326bff992841a0baca17c16c94ea99|0|0|636397146413883032&sdata=C1%2F8MXq%2Fh7NHgyxeKDkcHDcigtQjSztCaAeUxBzYZ3g%3D&reserved=0&gt;

Brandon

JSON’s types effectively end up matching specifically to primitives, of

which there is no mechanism to override the behavior of how a String gets
decoded for instance.

You can override the default behavior with your own custom init(from:)
implementation for your Codable struct:
https://developer.apple.com/documentation/swift/decodable/2894081-init

You can check Foundation source code (i.e., the URL struct) on how this can
be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

            <swift-corelibs-dev@swift.org>

···

From: "Sneed, Brandon via swift-corelibs-dev"
To: Tony Parker <anthony.parker@apple.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
            JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My
own json encode/decode library worked this way and it was really great,
however in trying to leverage Swift4 into it, or to replace it, I just
don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of
which there is no mechanism to override the behavior of how a String gets
decoded for instance. The only way I can think of to accomplish that is to
create *another* type, JSONString for example, but since String is a
struct, I can’t subclass it, and instead need to have the real value buried
inside of it … it seems to start getting messy very quickly. It also adds
the obfuscation of dealing with yet another type, which I’m not against,
but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker
<anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Itai Ferber <iferber@apple.com>, "swift-corelibs-dev@swift.org"
<swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is
being decoded. If, in a particular type, the “number” can be either a true
number or a string, then that type can try decoding it as one or the other
and fall back as required. That puts the responsibility of doing that kind
of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line
between numbers and strings automatically…

- Tony

      On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev < swift-corelibs-dev@swift.org> wrote:

      Hi Itai,

      No problem! Thanks for the heads up. Is there any way I could be
      involved? Happy to do the work to whatever guidance your team might
      have. I’m mostly just interested in it being there soon, hence
      volunteering.

      Thanks!

      Brandon Sneed

      From: <iferber@apple.com> on behalf of Itai Ferber <iferber@apple.com
      >
      Date: Wednesday, August 30, 2017 at 11:22 AM
      To: "Sneed, Brandon" <brsneed@ebay.com>
      Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
      Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities
      to JSON encode/decode

      Hi Brandon,
      Thanks for looking at this! We’ve got plans internally to potentially
      add a strategy to JSONEncoder/JSONDecoder to allow lenient
      conversions like this — i.e. implicitly stringify numbers (or parse
      them from string input), among some others.
      This would be opt-in for consumers of JSONDecoder while not requiring
      any special annotations on Codable types.
      — Itai
      On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
      Hi everyone,

      Just throwing this out to see if anyone else is working on this, or
      has opinions/suggestions on how it’s implemented. I’d like to add
      this to the Codable/JSONDecoder/JSONEncoder system if no one else is
      working on it.

      Type type conversion, I mean given this JSON payload:

      {
              "name": "Endeavor”,
              "abv": 8.9,
              "brewery": "Saint Arnold”,
              "style": "ipa"
      }

      and a struct defined as:

      struct Beer: Codable {
          let name: String
          let abv: String
          let brewery: String
          let style: BeerStyle
      }

      Notice that “abv” is a number in the JSON, but a String in the
      struct. I’d like to make it such that I can let the system know it’s
      ok to convert it from a number to a string as opposed to throwing an
      exception. The benefits are:

      1. It’s defensive; service types can change without causing my
      application to crash.
      2. It allows a developer to work with the types they want to
      work with as opposed to what the server provides, thus saving them
      time of writing a custom encode/decode code for all members.

      The argument against it that I’ve heard is generally “it’s a service
      bug, make them fix it”, which is valid but the reality is we’re not
      all in control of the services we injest. The same type of logic
      could be applied to a member name changing, though I haven’t seen
      this happen often in practice. I do see types in a json payload
      change with some frequency though. I think much of the reason stems
      from the fact that type conversion in javascript is effectively free,
      ie: you ask for a String, you get a String if possible.

      To implement this type conversion in practice, looking at it from the
      point of view using Codable/JSON(en/de)coder, one way would be to
      make it opt-in:

      struct Beer: Codable, CodingConvertible {
          let name: String
          let abv: String
          let brewery: String
          let style: BeerStyle
      }

      I like this because looking at the struct, the members still remain
      clear and relatively unambiguous. The downside is it’s unknown which
      member is likely to get converted. And since it’s opt-in, conversion
      doesn’t happen if the CodingConvertible conformance isn’t adhered to.

      Another option would be to box each type, like so:

      struct Beer: Codable {
          let name: String
          let abv: Convertible<String>
          let brewery: String
          let style: BeerStyle
      }

      This seems tedious for developers, but would show which types are
      being converted. It does however seriously weaken benefit #1 above.

      Those example usages above aside, I do think it’d be best if this
      conversion behavior was the default and no end-developer changes
      required. I think that could be done without impact to code that’s
      been already been written against the JSON en/decode bits.

      I’m very open to alternatives, other ideas, or anything else you
      might have to say on the subject. Thanks for reading!

      Brandon Sneed

      _______________________________________________
      swift-corelibs-dev mailing list
      swift-corelibs-dev@swift.org
      https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
      _______________________________________________
      swift-corelibs-dev mailing list
      swift-corelibs-dev@swift.org
      https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e=

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually get used in the decoding process. That being my preferred way, I tried it first. I chalked it not working up to Swift not knowing which of the 2 init(from decoder:) functions to call, mine or theirs. But, maybe there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

···

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance.

You can override the default behavior with your own custom init(from:) implementation for your Codable struct: https://developer.apple.com/documentation/swift/decodable/2894081-init&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdeveloper.apple.com%2Fdocumentation%2Fswift%2Fdecodable%2F2894081-init&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=oLr1Q10%2BztzwG%2BCXpMinBzJNTwSy%2FjoBsKm9Glg1%2FxY%3D&reserved=0&gt;

You can check Foundation source code (i.e., the URL struct) on how this can be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

[nactive hide details for "Sneed, Brandon via swift-corelibs-dev" ---08/30]"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi Tony, I like the idea that the type itself is responsible for the conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev" <swift-corelibs-dev@swift.org>
To: Tony Parker <anthony.parker@apple.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org

________________________________

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My own json encode/decode library worked this way and it was really great, however in trying to leverage Swift4 into it, or to replace it, I just don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance. The only way I can think of to accomplish that is to create *another* type, JSONString for example, but since String is a struct, I can’t subclass it, and instead need to have the real value buried inside of it … it seems to start getting messy very quickly. It also adds the obfuscation of dealing with yet another type, which I’m not against, but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Itai Ferber <iferber@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony
On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com<mailto:iferber@apple.com>> on behalf of Itai Ferber <iferber@apple.com<mailto:iferber@apple.com>>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,
Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.
— Itai
On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
"name": "Endeavor”,
"abv": 8.9,
"brewery": "Saint Arnold”,
"style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
let name: String
let abv: Convertible<String>
let brewery: String
let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C0e58a975be44418826d608d4efd427dc-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397141865218008-26sdata-3DytYIqDtMesw4NnpUbFmiWF2-252FKfxlawG4YuVWPJd099Y-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DrVZl8iT3jj1nzuDTCqZ1pkhQIZD3-Byi8PUj50swTUg%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=GkxX7xyhtHr1zqISNmjeBhvOkVoZdOihXcaugXSK9tA%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257Cf2eba37a5b40474e09b108d4efd5372d-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397146413883032-26sdata-3DC1-252F8MXq-252Fh7NHgyxeKDkcHDcigtQjSztCaAeUxBzYZ3g-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DLQ0cgWtC9rXRTDLu0W58VIukWrsRssHsIMGb9U6Y0MU%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=afQLw7%2FVip%2Bts1P60ALOHrTNap93519tWLjYzkS2o5Q%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e=&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev%26d%3DDwIGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DzRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=kUgv%2B3QRVpUH5JGBclTqYHheS%2FfaDPIWTrTk%2F%2BX8J%2Bs%3D&reserved=0&gt;

Brandon

I cooked up a simple example and it works as expected.

ylin@youming-mbpr:~/Swift/Configuration$ swift
Welcome to Apple Swift version 4.0-dev (LLVM 2dedb62a0b, Clang b9d76a314c,
Swift 0899bd328a). Type :help for assistance.
  1> import Foundation
  2> struct A: Codable {
  3. var integer: Int
  4.
  5. public init(integer: Int) {
  6. self.integer = integer
  7. }
  8.
  9. public init(from decoder: Decoder) throws {
10. print("Custom decoder")
11. let container = try decoder.container(keyedBy:
CodingKeys.self)
12. integer = try container.decode(Int.self, forKey: .integer)
13. }
14. }
15.
16. try! JSONDecoder().decode(A.self, from: JSONEncoder().encode(A
(integer: 42)))
Custom decoder
$R0: A = {
  integer = 42
}

You should be able to implement your custom init to convert the number into
a string and JSONDecoder should use that automatically.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

···

From: "Sneed, Brandon" <brsneed@ebay.com>
To: Youming Lin <ylin@us.ibm.com>
Cc: Tony Parker <anthony.parker@apple.com>,
            "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>,
            "swift-corelibs-dev-bounces@swift.org"
            <swift-corelibs-dev-bounces@swift.org>
Date: 08/30/2017 04:14 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
            JSON encode/decode

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it
actually get used in the decoding process. That being my preferred way, I
tried it first. I chalked it not working up to Swift not knowing which of
the 2 init(from decoder:) functions to call, mine or theirs. But, maybe
there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org"
<swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org"
<swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode

Brandon

JSON’s types effectively end up matching specifically to primitives, of

which there is no mechanism to override the behavior of how a String gets
decoded for instance.

You can override the default behavior with your own custom init(from:)
implementation for your Codable struct:
https://developer.apple.com/documentation/swift/decodable/2894081-init

You can check Foundation source code (i.e., the URL struct) on how this can
be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

nactive hide details for "Sneed, Brandon via swift-corelibs-dev" ---08/30
"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi
Tony, I like the idea that the type itself is responsible for the
conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev"
<swift-corelibs-dev@swift.org>
To: Tony Parker <anthony.parker@apple.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My
own json encode/decode library worked this way and it was really great,
however in trying to leverage Swift4 into it, or to replace it, I just
don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of
which there is no mechanism to override the behavior of how a String gets
decoded for instance. The only way I can think of to accomplish that is to
create *another* type, JSONString for example, but since String is a
struct, I can’t subclass it, and instead need to have the real value buried
inside of it … it seems to start getting messy very quickly. It also adds
the obfuscation of dealing with yet another type, which I’m not against,
but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker
<anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Itai Ferber <iferber@apple.com>, "swift-corelibs-dev@swift.org"
<swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is
being decoded. If, in a particular type, the “number” can be either a true
number or a string, then that type can try decoding it as one or the other
and fall back as required. That puts the responsibility of doing that kind
of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line
between numbers and strings automatically…

- Tony
            On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:

            Hi Itai,

            No problem! Thanks for the heads up. Is there any way I could
            be involved? Happy to do the work to whatever guidance your
            team might have. I’m mostly just interested in it being there
            soon, hence volunteering.

            Thanks!

            Brandon Sneed

            From: <iferber@apple.com> on behalf of Itai Ferber <
            iferber@apple.com>
            Date: Wednesday, August 30, 2017 at 11:22 AM
            To: "Sneed, Brandon" <brsneed@ebay.com>
            Cc: "swift-corelibs-dev@swift.org" <
            swift-corelibs-dev@swift.org>
            Subject: Re: [swift-corelibs-dev] Adding type conversion
            capabilities to JSON encode/decode

            Hi Brandon,
            Thanks for looking at this! We’ve got plans internally to
            potentially add a strategy to JSONEncoder/JSONDecoder to allow
            lenient conversions like this — i.e. implicitly stringify
            numbers (or parse them from string input), among some others.
            This would be opt-in for consumers of JSONDecoder while not
            requiring any special annotations on Codable types.
            — Itai
            On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
            Hi everyone,

            Just throwing this out to see if anyone else is working on
            this, or has opinions/suggestions on how it’s implemented. I’d
            like to add this to the Codable/JSONDecoder/JSONEncoder system
            if no one else is working on it.

            Type type conversion, I mean given this JSON payload:

            {
            "name": "Endeavor”,
            "abv": 8.9,
            "brewery": "Saint Arnold”,
            "style": "ipa"
            }

            and a struct defined as:

            struct Beer: Codable {
            let name: String
            let abv: String
            let brewery: String
            let style: BeerStyle
            }

            Notice that “abv” is a number in the JSON, but a String in the
            struct. I’d like to make it such that I can let the system know
            it’s ok to convert it from a number to a string as opposed to
            throwing an exception. The benefits are:

            1. It’s defensive; service types can change without causing my
            application to crash.
            2. It allows a developer to work with the types they want to
            work with as opposed to what the server provides, thus saving
            them time of writing a custom encode/decode code for all
            members.

            The argument against it that I’ve heard is generally “it’s a
            service bug, make them fix it”, which is valid but the reality
            is we’re not all in control of the services we injest. The same
            type of logic could be applied to a member name changing,
            though I haven’t seen this happen often in practice. I do see
            types in a json payload change with some frequency though. I
            think much of the reason stems from the fact that type
            conversion in javascript is effectively free, ie: you ask for a
            String, you get a String if possible.

            To implement this type conversion in practice, looking at it
            from the point of view using Codable/JSON(en/de)coder, one way
            would be to make it opt-in:

            struct Beer: Codable, CodingConvertible {
            let name: String
            let abv: String
            let brewery: String
            let style: BeerStyle
            }

            I like this because looking at the struct, the members still
            remain clear and relatively unambiguous. The downside is it’s
            unknown which member is likely to get converted. And since it’s
            opt-in, conversion doesn’t happen if the CodingConvertible
            conformance isn’t adhered to.

            Another option would be to box each type, like so:

            struct Beer: Codable {
            let name: String
            let abv: Convertible<String>
            let brewery: String
            let style: BeerStyle
            }

            This seems tedious for developers, but would show which types
            are being converted. It does however seriously weaken benefit
            #1 above.

            Those example usages above aside, I do think it’d be best if
            this conversion behavior was the default and no end-developer
            changes required. I think that could be done without impact to
            code that’s been already been written against the JSON
            en/decode bits.

            I’m very open to alternatives, other ideas, or anything else
            you might have to say on the subject. Thanks for reading!

            Brandon Sneed

            _______________________________________________
            swift-corelibs-dev mailing list
            swift-corelibs-dev@swift.org
            https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
            _______________________________________________
            swift-corelibs-dev mailing list
            swift-corelibs-dev@swift.org
            https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e=

Thanks Youming,

That’s not quite what I meant. I may have misinterpreted what Tony was saying though.

I wanted to do conversion on String, not the containing type. The problem of doing it on the containing type is that as soon as you need one field to be custom, you’re roped into handling all the others. For a small struct, not a big deal, for larger ones, it is. Something like this is what I tried:

import Cocoa

let jsonString = "{" +
    "\"name\": \"Endeavor\"," +
    "\"abv\": 8.9," +
    "\"brewery\": \"Saint Arnold\"," +
    "\"style\": \"ipa\"}"

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: String
}

extension String {
    init(from decoder: Decoder) throws {
        print("i got hit.")
        let value = try decoder.singleValueContainer().decode(String.self)
        self.init(value)
    }
}

let jsonData = jsonString.data(using: .utf8)
let decoder = JSONDecoder()
let beer = try! decoder.decode(Beer.self, from: jsonData!)

fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [__lldb_expr_17.Beer.(CodingKeys in _C8902E33F84CE6946081129DAF1824E1).abv], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil)): file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.59/src/swift/stdlib/public/core/ErrorType.swift, line 181

···

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 2:35 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

I cooked up a simple example and it works as expected.

ylin@youming-mbpr:~/Swift/Configuration$ swift
Welcome to Apple Swift version 4.0-dev (LLVM 2dedb62a0b, Clang b9d76a314c, Swift 0899bd328a). Type :help for assistance.
1> import Foundation
2> struct A: Codable {
3. var integer: Int
4.
5. public init(integer: Int) {
6. self.integer = integer
7. }
8.
9. public init(from decoder: Decoder) throws {
10. print("Custom decoder")
11. let container = try decoder.container(keyedBy: CodingKeys.self)
12. integer = try container.decode(Int.self, forKey: .integer)
13. }
14. }
15.
16. try! JSONDecoder().decode(A.self, from: JSONEncoder().encode(A(integer: 42)))
Custom decoder
$R0: A = {
integer = 42
}

You should be able to implement your custom init to convert the number into a string and JSONDecoder should use that automatically.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

[nactive hide details for "Sneed, Brandon" ---08/30/2017 04:14:57 PM---Tha]"Sneed, Brandon" ---08/30/2017 04:14:57 PM---Thanks Youming, Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually

From: "Sneed, Brandon" <brsneed@ebay.com>
To: Youming Lin <ylin@us.ibm.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Date: 08/30/2017 04:14 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

________________________________

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually get used in the decoding process. That being my preferred way, I tried it first. I chalked it not working up to Swift not knowing which of the 2 init(from decoder:) functions to call, mine or theirs. But, maybe there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance.

You can override the default behavior with your own custom init(from:) implementation for your Codable struct: https://developer.apple.com/documentation/swift/decodable/2894081-init&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Fdeveloper.apple.com-252Fdocumentation-252Fswift-252Fdecodable-252F2894081-2Dinit-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DoLr1Q10-252BztzwG-252BCXpMinBzJNTwSy-252FjoBsKm9Glg1-252FxY-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3Dh1azblXptqRwHqDQhejN9sSFa8dR-Gd8OkB7_6VwgNg%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=TIZrCfocLCJGcfOj%2B9V2FEiXPSTKN4hnL1Rm03GqHvk%3D&reserved=0&gt;

You can check Foundation source code (i.e., the URL struct) on how this can be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

[active hide details for "Sneed, Brandon via swift-corelibs-dev" ---08/30]"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi Tony, I like the idea that the type itself is responsible for the conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev" <swift-corelibs-dev@swift.org>
To: Tony Parker <anthony.parker@apple.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org

________________________________

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My own json encode/decode library worked this way and it was really great, however in trying to leverage Swift4 into it, or to replace it, I just don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance. The only way I can think of to accomplish that is to create *another* type, JSONString for example, but since String is a struct, I can’t subclass it, and instead need to have the real value buried inside of it … it seems to start getting messy very quickly. It also adds the obfuscation of dealing with yet another type, which I’m not against, but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Itai Ferber <iferber@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony
On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com<mailto:iferber@apple.com>> on behalf of Itai Ferber <iferber@apple.com<mailto:iferber@apple.com>>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,
Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.
— Itai
On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
"name": "Endeavor”,
"abv": 8.9,
"brewery": "Saint Arnold”,
"style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
let name: String
let abv: Convertible<String>
let brewery: String
let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C0e58a975be44418826d608d4efd427dc-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397141865218008-26sdata-3DytYIqDtMesw4NnpUbFmiWF2-252FKfxlawG4YuVWPJd099Y-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DrVZl8iT3jj1nzuDTCqZ1pkhQIZD3-Byi8PUj50swTUg%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=GkxX7xyhtHr1zqISNmjeBhvOkVoZdOihXcaugXSK9tA%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257Cf2eba37a5b40474e09b108d4efd5372d-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397146413883032-26sdata-3DC1-252F8MXq-252Fh7NHgyxeKDkcHDcigtQjSztCaAeUxBzYZ3g-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DLQ0cgWtC9rXRTDLu0W58VIukWrsRssHsIMGb9U6Y0MU%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=afQLw7%2FVip%2Bts1P60ALOHrTNap93519tWLjYzkS2o5Q%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e=&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Furldefense.proofpoint.com-252Fv2-252Furl-253Fu-253Dhttps-2D3A-5F-5Flists.swift.org-5Fmailman-5Flistinfo-5Fswift-2D2Dcorelibs-2D2Ddev-2526d-253DDwIGaQ-2526c-253Djf-5FiaSHvJObTbx-2DsiA1ZOg-2526r-253DgkRZBtsmKeGPCOlAIRJoOA-2526m-253DViDSVPImta3StTVAcktby2PMF-5F-2Ddu5itzz47jo-2DtNHg-2526s-253DzRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-2Dot9-5FpwAgqI-2526e-253D-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DkUgv-252B3QRVpUH5JGBclTqYHheS-252FfaDPIWTrTk-252F-252BX8J-252Bs-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3DlhWK6MIAPUmU4rsIhtD7P7EgacPwfGk17SvpQdMJogc%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=jJucdx3j9pb2ylcsHYaVAtze%2B%2BQWr%2F%2Bm2GpBRlHaBTk%3D&reserved=0&gt;

I haven’t tried this myself yet, but you could imagine creating a type which represents an ABV and decodes using a single value container. Then, your custom behavior goes into the Codable implementation of this ABV type.

Struct Beer then looks like:

struct Beer: Codable {
    let name: String
    let abv: ABV
    …
}

ABV can have API on it to get the numeric value or String value; or that could go into Beer and it would abstract the ABV type from callers.

- Tony

···

On Aug 30, 2017, at 2:42 PM, Sneed, Brandon <brsneed@ebay.com> wrote:

Thanks Youming,

That’s not quite what I meant. I may have misinterpreted what Tony was saying though.

I wanted to do conversion on String, not the containing type. The problem of doing it on the containing type is that as soon as you need one field to be custom, you’re roped into handling all the others. For a small struct, not a big deal, for larger ones, it is. Something like this is what I tried:

import Cocoa

let jsonString = "{" +
    "\"name\": \"Endeavor\"," +
    "\"abv\": 8.9," +
    "\"brewery\": \"Saint Arnold\"," +
    "\"style\": \"ipa\"}"

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: String
}

extension String {
    init(from decoder: Decoder) throws {
        print("i got hit.")
        let value = try decoder.singleValueContainer().decode(String.self)
        self.init(value)
    }
}

let jsonData = jsonString.data(using: .utf8)
let decoder = JSONDecoder()
let beer = try! decoder.decode(Beer.self, from: jsonData!)

fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [__lldb_expr_17.Beer.(CodingKeys in _C8902E33F84CE6946081129DAF1824E1).abv], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil)): file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.59/src/swift/stdlib/public/core/ErrorType.swift, line 181

From: Youming Lin <ylin@us.ibm.com <mailto:ylin@us.ibm.com>>
Date: Wednesday, August 30, 2017 at 2:35 PM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

I cooked up a simple example and it works as expected.

ylin@youming-mbpr:~/Swift/Configuration$ swift
Welcome to Apple Swift version 4.0-dev (LLVM 2dedb62a0b, Clang b9d76a314c, Swift 0899bd328a). Type :help for assistance.
1> import Foundation
2> struct A: Codable {
3. var integer: Int
4.
5. public init(integer: Int) {
6. self.integer = integer
7. }
8.
9. public init(from decoder: Decoder) throws {
10. print("Custom decoder")
11. let container = try decoder.container(keyedBy: CodingKeys.self)
12. integer = try container.decode(Int.self, forKey: .integer)
13. }
14. }
15.
16. try! JSONDecoder().decode(A.self, from: JSONEncoder().encode(A(integer: 42)))
Custom decoder
$R0: A = {
integer = 42
}

You should be able to implement your custom init to convert the number into a string and JSONDecoder should use that automatically.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

<image001.gif>"Sneed, Brandon" ---08/30/2017 04:14:57 PM---Thanks Youming, Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually

From: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
To: Youming Lin <ylin@us.ibm.com <mailto:ylin@us.ibm.com>>
Cc: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>>
Date: 08/30/2017 04:14 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually get used in the decoding process. That being my preferred way, I tried it first. I chalked it not working up to Swift not knowing which of the 2 init(from decoder:) functions to call, mine or theirs. But, maybe there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

From: Youming Lin <ylin@us.ibm.com <mailto:ylin@us.ibm.com>>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Brandon

>JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance.

You can override the default behavior with your own custom init(from:) implementation for your Codable struct: https://developer.apple.com/documentation/swift/decodable/2894081-init <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Fdeveloper.apple.com-252Fdocumentation-252Fswift-252Fdecodable-252F2894081-2Dinit-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DoLr1Q10-252BztzwG-252BCXpMinBzJNTwSy-252FjoBsKm9Glg1-252FxY-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3Dh1azblXptqRwHqDQhejN9sSFa8dR-Gd8OkB7_6VwgNg%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=TIZrCfocLCJGcfOj%2B9V2FEiXPSTKN4hnL1Rm03GqHvk%3D&reserved=0&gt;

You can check Foundation source code (i.e., the URL struct) on how this can be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

<image002.gif>"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi Tony, I like the idea that the type itself is responsible for the conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
To: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>
Cc: "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My own json encode/decode library worked this way and it was really great, however in trying to leverage Swift4 into it, or to replace it, I just don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance. The only way I can think of to accomplish that is to create *another* type, JSONString for example, but since String is a struct, I can’t subclass it, and instead need to have the real value buried inside of it … it seems to start getting messy very quickly. It also adds the obfuscation of dealing with yet another type, which I’m not against, but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com <mailto:anthony.parker@apple.com>> on behalf of Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: Itai Ferber <iferber@apple.com <mailto:iferber@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony
On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com <mailto:iferber@apple.com>> on behalf of Itai Ferber <iferber@apple.com <mailto:iferber@apple.com>>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,
Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.
— Itai
On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
"name": "Endeavor”,
"abv": 8.9,
"brewery": "Saint Arnold”,
"style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
let name: String
let abv: Convertible<String>
let brewery: String
let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C0e58a975be44418826d608d4efd427dc-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397141865218008-26sdata-3DytYIqDtMesw4NnpUbFmiWF2-252FKfxlawG4YuVWPJd099Y-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DrVZl8iT3jj1nzuDTCqZ1pkhQIZD3-Byi8PUj50swTUg%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=GkxX7xyhtHr1zqISNmjeBhvOkVoZdOihXcaugXSK9tA%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257Cf2eba37a5b40474e09b108d4efd5372d-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397146413883032-26sdata-3DC1-252F8MXq-252Fh7NHgyxeKDkcHDcigtQjSztCaAeUxBzYZ3g-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DLQ0cgWtC9rXRTDLu0W58VIukWrsRssHsIMGb9U6Y0MU%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=afQLw7%2FVip%2Bts1P60ALOHrTNap93519tWLjYzkS2o5Q%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e= <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Furldefense.proofpoint.com-252Fv2-252Furl-253Fu-253Dhttps-2D3A-5F-5Flists.swift.org-5Fmailman-5Flistinfo-5Fswift-2D2Dcorelibs-2D2Ddev-2526d-253DDwIGaQ-2526c-253Djf-5FiaSHvJObTbx-2DsiA1ZOg-2526r-253DgkRZBtsmKeGPCOlAIRJoOA-2526m-253DViDSVPImta3StTVAcktby2PMF-5F-2Ddu5itzz47jo-2DtNHg-2526s-253DzRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-2Dot9-5FpwAgqI-2526e-253D-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DkUgv-252B3QRVpUH5JGBclTqYHheS-252FfaDPIWTrTk-252F-252BX8J-252Bs-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3DlhWK6MIAPUmU4rsIhtD7P7EgacPwfGk17SvpQdMJogc%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=jJucdx3j9pb2ylcsHYaVAtze%2B%2BQWr%2F%2Bm2GpBRlHaBTk%3D&reserved=0&gt;

Brandon

Sorry, I didn't realize you want it on the String type since you used other
string ivars in your example as well.

I'm not sure that forcing all numbers to be valid decoded strings is a good
idea, because this behavior gets applied to other string ivars that you may
not want to be compatible with numbers, which is the inverse of the problem
you stated.

A custom Codable type to represent number-equivalent strings is a better
solution I think.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

···

From: "Sneed, Brandon" <brsneed@ebay.com>
To: Youming Lin <ylin@us.ibm.com>
Cc: Tony Parker <anthony.parker@apple.com>,
            "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>,
            "swift-corelibs-dev-bounces@swift.org"
            <swift-corelibs-dev-bounces@swift.org>
Date: 08/30/2017 04:42 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
            JSON encode/decode

Thanks Youming,

That’s not quite what I meant. I may have misinterpreted what Tony was
saying though.

I wanted to do conversion on String, not the containing type. The problem
of doing it on the containing type is that as soon as you need one field to
be custom, you’re roped into handling all the others. For a small struct,
not a big deal, for larger ones, it is. Something like this is what I
tried:

import Cocoa

let jsonString = "{" +
    "\"name\": \"Endeavor\"," +
    "\"abv\": 8.9," +
    "\"brewery\": \"Saint Arnold\"," +
    "\"style\": \"ipa\"}"

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: String
}

extension String {
    init(from decoder: Decoder) throws {
        print("i got hit.")
        let value = try decoder.singleValueContainer().decode(String.self)
        self.init(value)
    }
}

let jsonData = jsonString.data(using: .utf8)
let decoder = JSONDecoder()
let beer = try! decoder.decode(Beer.self, from: jsonData!)

fatal error: 'try!' expression unexpectedly raised an error:
Swift.DecodingError.typeMismatch(Swift.String, Swift.DecodingError.Context
(codingPath: [__lldb_expr_17.Beer.(CodingKeys in
_C8902E33F84CE6946081129DAF1824E1).abv], debugDescription: "Expected to
decode String but found a number instead.", underlyingError: nil)):
file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.59/src/swift/stdlib/public/core/ErrorType.swift,
line 181

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 2:35 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org"
<swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org"
<swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode

Brandon

I cooked up a simple example and it works as expected.

ylin@youming-mbpr:~/Swift/Configuration$ swift
Welcome to Apple Swift version 4.0-dev (LLVM 2dedb62a0b, Clang b9d76a314c,
Swift 0899bd328a). Type :help for assistance.
1> import Foundation
2> struct A: Codable {
3. var integer: Int
4.
5. public init(integer: Int) {
6. self.integer = integer
7. }
8.
9. public init(from decoder: Decoder) throws {
10. print("Custom decoder")
11. let container = try decoder.container(keyedBy: CodingKeys.self)
12. integer = try container.decode(Int.self, forKey: .integer)
13. }
14. }
15.
16. try! JSONDecoder().decode(A.self, from: JSONEncoder().encode(A(integer:
42)))
Custom decoder
$R0: A = {
integer = 42
}

You should be able to implement your custom init to convert the number into
a string and JSONDecoder should use that automatically.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

nactive hide details for "Sneed, Brandon" ---08/30/2017 04:14:57 PM---Tha
"Sneed, Brandon" ---08/30/2017 04:14:57 PM---Thanks Youming, Ok, thanks! I
did try that, but I can’t seem to figure out how to make it actually

From: "Sneed, Brandon" <brsneed@ebay.com>
To: Youming Lin <ylin@us.ibm.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org"
<swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org"
<swift-corelibs-dev-bounces@swift.org>
Date: 08/30/2017 04:14 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it
actually get used in the decoding process. That being my preferred way, I
tried it first. I chalked it not working up to Swift not knowing which of
the 2 init(from decoder:) functions to call, mine or theirs. But, maybe
there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org"
<swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org"
<swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode

Brandon

JSON’s types effectively end up matching specifically to primitives, of

which there is no mechanism to override the behavior of how a String gets
decoded for instance.

You can override the default behavior with your own custom init(from:)
implementation for your Codable struct:
https://developer.apple.com/documentation/swift/decodable/2894081-init

You can check Foundation source code (i.e., the URL struct) on how this can
be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

active hide details for "Sneed, Brandon via swift-corelibs-dev" ---08/30
"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi
Tony, I like the idea that the type itself is responsible for the
conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev"
<swift-corelibs-dev@swift.org>
To: Tony Parker <anthony.parker@apple.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My
own json encode/decode library worked this way and it was really great,
however in trying to leverage Swift4 into it, or to replace it, I just
don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of
which there is no mechanism to override the behavior of how a String gets
decoded for instance. The only way I can think of to accomplish that is to
create *another* type, JSONString for example, but since String is a
struct, I can’t subclass it, and instead need to have the real value buried
inside of it … it seems to start getting messy very quickly. It also adds
the obfuscation of dealing with yet another type, which I’m not against,
but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker
<anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Itai Ferber <iferber@apple.com>, "swift-corelibs-dev@swift.org"
<swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to
JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is
being decoded. If, in a particular type, the “number” can be either a true
number or a string, then that type can try decoding it as one or the other
and fall back as required. That puts the responsibility of doing that kind
of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line
between numbers and strings automatically…

- Tony
                        On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:

                        Hi Itai,

                        No problem! Thanks for the heads up. Is there any
                        way I could be involved? Happy to do the work to
                        whatever guidance your team might have. I’m mostly
                        just interested in it being there soon, hence
                        volunteering.

                        Thanks!

                        Brandon Sneed

                        From: <iferber@apple.com> on behalf of Itai Ferber
                        <iferber@apple.com>
                        Date: Wednesday, August 30, 2017 at 11:22 AM
                        To: "Sneed, Brandon" <brsneed@ebay.com>
                        Cc: "swift-corelibs-dev@swift.org" <
                        swift-corelibs-dev@swift.org>
                        Subject: Re: [swift-corelibs-dev] Adding type
                        conversion capabilities to JSON encode/decode

                        Hi Brandon,
                        Thanks for looking at this! We’ve got plans
                        internally to potentially add a strategy to
                        JSONEncoder/JSONDecoder to allow lenient
                        conversions like this — i.e. implicitly stringify
                        numbers (or parse them from string input), among
                        some others.
                        This would be opt-in for consumers of JSONDecoder
                        while not requiring any special annotations on
                        Codable types.
                        — Itai
                        On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
                        Hi everyone,

                        Just throwing this out to see if anyone else is
                        working on this, or has opinions/suggestions on how
                        it’s implemented. I’d like to add this to the
                        Codable/JSONDecoder/JSONEncoder system if no one
                        else is working on it.

                        Type type conversion, I mean given this JSON
                        payload:

                        {
                        "name": "Endeavor”,
                        "abv": 8.9,
                        "brewery": "Saint Arnold”,
                        "style": "ipa"
                        }

                        and a struct defined as:

                        struct Beer: Codable {
                        let name: String
                        let abv: String
                        let brewery: String
                        let style: BeerStyle
                        }

                        Notice that “abv” is a number in the JSON, but a
                        String in the struct. I’d like to make it such that
                        I can let the system know it’s ok to convert it
                        from a number to a string as opposed to throwing an
                        exception. The benefits are:

                        1. It’s defensive; service types can change without
                        causing my application to crash.
                        2. It allows a developer to work with the types
                        they want to work with as opposed to what the
                        server provides, thus saving them time of writing a
                        custom encode/decode code for all members.

                        The argument against it that I’ve heard is
                        generally “it’s a service bug, make them fix it”,
                        which is valid but the reality is we’re not all in
                        control of the services we injest. The same type of
                        logic could be applied to a member name changing,
                        though I haven’t seen this happen often in
                        practice. I do see types in a json payload change
                        with some frequency though. I think much of the
                        reason stems from the fact that type conversion in
                        javascript is effectively free, ie: you ask for a
                        String, you get a String if possible.

                        To implement this type conversion in practice,
                        looking at it from the point of view using
                        Codable/JSON(en/de)coder, one way would be to make
                        it opt-in:

                        struct Beer: Codable, CodingConvertible {
                        let name: String
                        let abv: String
                        let brewery: String
                        let style: BeerStyle
                        }

                        I like this because looking at the struct, the
                        members still remain clear and relatively
                        unambiguous. The downside is it’s unknown which
                        member is likely to get converted. And since it’s
                        opt-in, conversion doesn’t happen if the
                        CodingConvertible conformance isn’t adhered to.

                        Another option would be to box each type, like so:

                        struct Beer: Codable {
                        let name: String
                        let abv: Convertible<String>
                        let brewery: String
                        let style: BeerStyle
                        }

                        This seems tedious for developers, but would show
                        which types are being converted. It does however
                        seriously weaken benefit #1 above.

                        Those example usages above aside, I do think it’d
                        be best if this conversion behavior was the default
                        and no end-developer changes required. I think that
                        could be done without impact to code that’s been
                        already been written against the JSON en/decode
                        bits.

                        I’m very open to alternatives, other ideas, or
                        anything else you might have to say on the subject.
                        Thanks for reading!

                        Brandon Sneed

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

                        _______________________________________________
                        swift-corelibs-dev mailing list
                        swift-corelibs-dev@swift.org
                        https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e=

Thanks Tony,

Ah. That should work, and covers benefit #2 I mentioned very nicely. Only downside is that as a developer on an app I may not expect that type to change on the server side so I wouldn’t do it by default, and when it does happen, I then need to apply it to each of its siblings because if it can happen to one, it can happen to the others.

Javascript and GSON handle this in a relatively safe way. I think us having a way to opt-in to the same capabilities is good. When I say opt-in, I mean at the containing-struct level, not necessarily per member, nor do I want to do a custom init every time. I’m sure there’s a happy place in the middle, just not sure what it is.

I do also want to add that I very much appreciate the discussion. We’re having one internally too, and the divide seems to be about the same as what’s on the mailing list (which seems about 50/50).

Brandon Sneed

···

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 3:04 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Youming Lin <ylin@us.ibm.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I haven’t tried this myself yet, but you could imagine creating a type which represents an ABV and decodes using a single value container. Then, your custom behavior goes into the Codable implementation of this ABV type.

Struct Beer then looks like:

struct Beer: Codable {
    let name: String
    let abv: ABV
    …
}

ABV can have API on it to get the numeric value or String value; or that could go into Beer and it would abstract the ABV type from callers.

- Tony

On Aug 30, 2017, at 2:42 PM, Sneed, Brandon <brsneed@ebay.com<mailto:brsneed@ebay.com>> wrote:

Thanks Youming,

That’s not quite what I meant. I may have misinterpreted what Tony was saying though.

I wanted to do conversion on String, not the containing type. The problem of doing it on the containing type is that as soon as you need one field to be custom, you’re roped into handling all the others. For a small struct, not a big deal, for larger ones, it is. Something like this is what I tried:

import Cocoa

let jsonString = "{" +
    "\"name\": \"Endeavor\"," +
    "\"abv\": 8.9," +
    "\"brewery\": \"Saint Arnold\"," +
    "\"style\": \"ipa\"}"

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: String
}

extension String {
    init(from decoder: Decoder) throws {
        print("i got hit.")
        let value = try decoder.singleValueContainer().decode(String.self)
        self.init(value)
    }
}

let jsonData = jsonString.data(using: .utf8)
let decoder = JSONDecoder()
let beer = try! decoder.decode(Beer.self, from: jsonData!)

fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [__lldb_expr_17.Beer.(CodingKeys in _C8902E33F84CE6946081129DAF1824E1).abv], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil)): file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.59/src/swift/stdlib/public/core/ErrorType.swift, line 181

From: Youming Lin <ylin@us.ibm.com<mailto:ylin@us.ibm.com>>
Date: Wednesday, August 30, 2017 at 2:35 PM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: Tony Parker <anthony.parker@apple.com<mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org<mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org<mailto:swift-corelibs-dev-bounces@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

I cooked up a simple example and it works as expected.

ylin@youming-mbpr:~/Swift/Configuration$ swift
Welcome to Apple Swift version 4.0-dev (LLVM 2dedb62a0b, Clang b9d76a314c, Swift 0899bd328a). Type :help for assistance.
1> import Foundation
2> struct A: Codable {
3. var integer: Int
4.
5. public init(integer: Int) {
6. self.integer = integer
7. }
8.
9. public init(from decoder: Decoder) throws {
10. print("Custom decoder")
11. let container = try decoder.container(keyedBy: CodingKeys.self)
12. integer = try container.decode(Int.self, forKey: .integer)
13. }
14. }
15.
16. try! JSONDecoder().decode(A.self, from: JSONEncoder().encode(A(integer: 42)))
Custom decoder
$R0: A = {
integer = 42
}

You should be able to implement your custom init to convert the number into a string and JSONDecoder should use that automatically.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

<image001.gif>"Sneed, Brandon" ---08/30/2017 04:14:57 PM---Thanks Youming, Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually

From: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
To: Youming Lin <ylin@us.ibm.com<mailto:ylin@us.ibm.com>>
Cc: Tony Parker <anthony.parker@apple.com<mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org<mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org<mailto:swift-corelibs-dev-bounces@swift.org>>
Date: 08/30/2017 04:14 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
________________________________

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually get used in the decoding process. That being my preferred way, I tried it first. I chalked it not working up to Swift not knowing which of the 2 init(from decoder:) functions to call, mine or theirs. But, maybe there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

From: Youming Lin <ylin@us.ibm.com<mailto:ylin@us.ibm.com>>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: Tony Parker <anthony.parker@apple.com<mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org<mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org<mailto:swift-corelibs-dev-bounces@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Brandon

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance.

You can override the default behavior with your own custom init(from:) implementation for your Codable struct: https://developer.apple.com/documentation/swift/decodable/2894081-init&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Fdeveloper.apple.com-252Fdocumentation-252Fswift-252Fdecodable-252F2894081-2Dinit-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DoLr1Q10-252BztzwG-252BCXpMinBzJNTwSy-252FjoBsKm9Glg1-252FxY-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3Dh1azblXptqRwHqDQhejN9sSFa8dR-Gd8OkB7_6VwgNg%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=TIZrCfocLCJGcfOj%2B9V2FEiXPSTKN4hnL1Rm03GqHvk%3D&reserved=0&gt;

You can check Foundation source code (i.e., the URL struct) on how this can be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

<image002.gif>"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi Tony, I like the idea that the type itself is responsible for the conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
To: Tony Parker <anthony.parker@apple.com<mailto:anthony.parker@apple.com>>
Cc: "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org<mailto:swift-corelibs-dev-bounces@swift.org>
________________________________

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My own json encode/decode library worked this way and it was really great, however in trying to leverage Swift4 into it, or to replace it, I just don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance. The only way I can think of to accomplish that is to create *another* type, JSONString for example, but since String is a struct, I can’t subclass it, and instead need to have the real value buried inside of it … it seems to start getting messy very quickly. It also adds the obfuscation of dealing with yet another type, which I’m not against, but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com<mailto:anthony.parker@apple.com>> on behalf of Tony Parker <anthony.parker@apple.com<mailto:anthony.parker@apple.com>>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: Itai Ferber <iferber@apple.com<mailto:iferber@apple.com>>, "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony
On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com<mailto:iferber@apple.com>> on behalf of Itai Ferber <iferber@apple.com<mailto:iferber@apple.com>>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,
Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.
— Itai
On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
"name": "Endeavor”,
"abv": 8.9,
"brewery": "Saint Arnold”,
"style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
let name: String
let abv: Convertible<String>
let brewery: String
let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C0e58a975be44418826d608d4efd427dc-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397141865218008-26sdata-3DytYIqDtMesw4NnpUbFmiWF2-252FKfxlawG4YuVWPJd099Y-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DrVZl8iT3jj1nzuDTCqZ1pkhQIZD3-Byi8PUj50swTUg%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=GkxX7xyhtHr1zqISNmjeBhvOkVoZdOihXcaugXSK9tA%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257Cf2eba37a5b40474e09b108d4efd5372d-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397146413883032-26sdata-3DC1-252F8MXq-252Fh7NHgyxeKDkcHDcigtQjSztCaAeUxBzYZ3g-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DLQ0cgWtC9rXRTDLu0W58VIukWrsRssHsIMGb9U6Y0MU%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=afQLw7%2FVip%2Bts1P60ALOHrTNap93519tWLjYzkS2o5Q%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e=&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Furldefense.proofpoint.com-252Fv2-252Furl-253Fu-253Dhttps-2D3A-5F-5Flists.swift.org-5Fmailman-5Flistinfo-5Fswift-2D2Dcorelibs-2D2Ddev-2526d-253DDwIGaQ-2526c-253Djf-5FiaSHvJObTbx-2DsiA1ZOg-2526r-253DgkRZBtsmKeGPCOlAIRJoOA-2526m-253DViDSVPImta3StTVAcktby2PMF-5F-2Ddu5itzz47jo-2DtNHg-2526s-253DzRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-2Dot9-5FpwAgqI-2526e-253D-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DkUgv-252B3QRVpUH5JGBclTqYHheS-252FfaDPIWTrTk-252F-252BX8J-252Bs-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3DlhWK6MIAPUmU4rsIhtD7P7EgacPwfGk17SvpQdMJogc%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=jJucdx3j9pb2ylcsHYaVAtze%2B%2BQWr%2F%2Bm2GpBRlHaBTk%3D&reserved=0&gt;

Hi Youming,

No worries. Some of the verbage overlaps enough that it makes the conversation a little difficult to follow.

The jist is basically that if I type my struct with an Int inside, the JSON payload contains a string, I want an Int back if at all possible. If my struct has a string, the JSON payload has an int, I want the string. I want the struct the type specifies to at least be attempted to be given back before failing.

That’s not to say I’m only talking about doing this with Strings and Ints, just using it as an example for the conversation.

Hopefully that helps.

Brandon Sneed

···

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 3:19 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

Sorry, I didn't realize you want it on the String type since you used other string ivars in your example as well.

I'm not sure that forcing all numbers to be valid decoded strings is a good idea, because this behavior gets applied to other string ivars that you may not want to be compatible with numbers, which is the inverse of the problem you stated.

A custom Codable type to represent number-equivalent strings is a better solution I think.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

[nactive hide details for "Sneed, Brandon" ---08/30/2017 04:42:39 PM---Tha]"Sneed, Brandon" ---08/30/2017 04:42:39 PM---Thanks Youming, That’s not quite what I meant. I may have misinterpreted what Tony was saying thoug

From: "Sneed, Brandon" <brsneed@ebay.com>
To: Youming Lin <ylin@us.ibm.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Date: 08/30/2017 04:42 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

________________________________

Thanks Youming,

That’s not quite what I meant. I may have misinterpreted what Tony was saying though.

I wanted to do conversion on String, not the containing type. The problem of doing it on the containing type is that as soon as you need one field to be custom, you’re roped into handling all the others. For a small struct, not a big deal, for larger ones, it is. Something like this is what I tried:

import Cocoa

let jsonString = "{" +
"\"name\": \"Endeavor\"," +
"\"abv\": 8.9," +
"\"brewery\": \"Saint Arnold\"," +
"\"style\": \"ipa\"}"

struct Beer: Codable {
let name: String
let abv: String
let brewery: String
let style: String
}

extension String {
init(from decoder: Decoder) throws {
print("i got hit.")
let value = try decoder.singleValueContainer().decode(String.self)
self.init(value)
}
}

let jsonData = jsonString.data(using: .utf8)
let decoder = JSONDecoder()
let beer = try! decoder.decode(Beer.self, from: jsonData!)

fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [__lldb_expr_17.Beer.(CodingKeys in _C8902E33F84CE6946081129DAF1824E1).abv], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil)): file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.59/src/swift/stdlib/public/core/ErrorType.swift, line 181

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 2:35 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

I cooked up a simple example and it works as expected.

ylin@youming-mbpr:~/Swift/Configuration$ swift
Welcome to Apple Swift version 4.0-dev (LLVM 2dedb62a0b, Clang b9d76a314c, Swift 0899bd328a). Type :help for assistance.
1> import Foundation
2> struct A: Codable {
3. var integer: Int
4.
5. public init(integer: Int) {
6. self.integer = integer
7. }
8.
9. public init(from decoder: Decoder) throws {
10. print("Custom decoder")
11. let container = try decoder.container(keyedBy: CodingKeys.self)
12. integer = try container.decode(Int.self, forKey: .integer)
13. }
14. }
15.
16. try! JSONDecoder().decode(A.self, from: JSONEncoder().encode(A(integer: 42)))
Custom decoder
$R0: A = {
integer = 42
}

You should be able to implement your custom init to convert the number into a string and JSONDecoder should use that automatically.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

[active hide details for "Sneed, Brandon" ---08/30/2017 04:14:57 PM---Tha]"Sneed, Brandon" ---08/30/2017 04:14:57 PM---Thanks Youming, Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually

From: "Sneed, Brandon" <brsneed@ebay.com>
To: Youming Lin <ylin@us.ibm.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Date: 08/30/2017 04:14 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

________________________________

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually get used in the decoding process. That being my preferred way, I tried it first. I chalked it not working up to Swift not knowing which of the 2 init(from decoder:) functions to call, mine or theirs. But, maybe there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

From: Youming Lin <ylin@us.ibm.com>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Tony Parker <anthony.parker@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>, "swift-corelibs-dev-bounces@swift.org" <swift-corelibs-dev-bounces@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance.

You can override the default behavior with your own custom init(from:) implementation for your Codable struct: https://developer.apple.com/documentation/swift/decodable/2894081-init&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Fdeveloper.apple.com-252Fdocumentation-252Fswift-252Fdecodable-252F2894081-2Dinit-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DoLr1Q10-252BztzwG-252BCXpMinBzJNTwSy-252FjoBsKm9Glg1-252FxY-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3Dh1azblXptqRwHqDQhejN9sSFa8dR-Gd8OkB7_6VwgNg%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=TIZrCfocLCJGcfOj%2B9V2FEiXPSTKN4hnL1Rm03GqHvk%3D&reserved=0&gt;

You can check Foundation source code (i.e., the URL struct) on how this can be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

[ctive hide details for "Sneed, Brandon via swift-corelibs-dev" ---08/30]"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi Tony, I like the idea that the type itself is responsible for the conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev" <swift-corelibs-dev@swift.org>
To: Tony Parker <anthony.parker@apple.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org

________________________________

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My own json encode/decode library worked this way and it was really great, however in trying to leverage Swift4 into it, or to replace it, I just don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance. The only way I can think of to accomplish that is to create *another* type, JSONString for example, but since String is a struct, I can’t subclass it, and instead need to have the real value buried inside of it … it seems to start getting messy very quickly. It also adds the obfuscation of dealing with yet another type, which I’m not against, but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Itai Ferber <iferber@apple.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony
On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com<mailto:iferber@apple.com>> on behalf of Itai Ferber <iferber@apple.com<mailto:iferber@apple.com>>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com<mailto:brsneed@ebay.com>>
Cc: "swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,
Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.
— Itai
On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
"name": "Endeavor”,
"abv": 8.9,
"brewery": "Saint Arnold”,
"style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
let name: String
let abv: Convertible<String>
let brewery: String
let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C0e58a975be44418826d608d4efd427dc-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397141865218008-26sdata-3DytYIqDtMesw4NnpUbFmiWF2-252FKfxlawG4YuVWPJd099Y-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DrVZl8iT3jj1nzuDTCqZ1pkhQIZD3-Byi8PUj50swTUg%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=GkxX7xyhtHr1zqISNmjeBhvOkVoZdOihXcaugXSK9tA%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org<mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257Cf2eba37a5b40474e09b108d4efd5372d-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397146413883032-26sdata-3DC1-252F8MXq-252Fh7NHgyxeKDkcHDcigtQjSztCaAeUxBzYZ3g-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DLQ0cgWtC9rXRTDLu0W58VIukWrsRssHsIMGb9U6Y0MU%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=afQLw7%2FVip%2Bts1P60ALOHrTNap93519tWLjYzkS2o5Q%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e=&lt;https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Furldefense.proofpoint.com-252Fv2-252Furl-253Fu-253Dhttps-2D3A-5F-5Flists.swift.org-5Fmailman-5Flistinfo-5Fswift-2D2Dcorelibs-2D2Ddev-2526d-253DDwIGaQ-2526c-253Djf-5FiaSHvJObTbx-2DsiA1ZOg-2526r-253DgkRZBtsmKeGPCOlAIRJoOA-2526m-253DViDSVPImta3StTVAcktby2PMF-5F-2Ddu5itzz47jo-2DtNHg-2526s-253DzRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-2Dot9-5FpwAgqI-2526e-253D-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DkUgv-252B3QRVpUH5JGBclTqYHheS-252FfaDPIWTrTk-252F-252BX8J-252Bs-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3DlhWK6MIAPUmU4rsIhtD7P7EgacPwfGk17SvpQdMJogc%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=jJucdx3j9pb2ylcsHYaVAtze%2B%2BQWr%2F%2Bm2GpBRlHaBTk%3D&reserved=0&gt;

Thanks Tony,

Ah. That should work, and covers benefit #2 I mentioned very nicely. Only downside is that as a developer on an app I may not expect that type to change on the server side so I wouldn’t do it by default, and when it does happen, I then need to apply it to each of its siblings because if it can happen to one, it can happen to the others.

In this case, the server decides to send a String instead of a numeric value for many kinds of types?

I understand that some JSON libraries have options to stringify all numeric values in an attempt to preserve ‘exactness’, although I would argue that this depends on what you do with the numeric value on the other side…

- Tony

···

On Aug 30, 2017, at 3:12 PM, Sneed, Brandon <brsneed@ebay.com> wrote:

Javascript and GSON handle this in a relatively safe way. I think us having a way to opt-in to the same capabilities is good. When I say opt-in, I mean at the containing-struct level, not necessarily per member, nor do I want to do a custom init every time. I’m sure there’s a happy place in the middle, just not sure what it is.

I do also want to add that I very much appreciate the discussion. We’re having one internally too, and the divide seems to be about the same as what’s on the mailing list (which seems about 50/50).

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 3:04 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Youming Lin <ylin@us.ibm.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I haven’t tried this myself yet, but you could imagine creating a type which represents an ABV and decodes using a single value container. Then, your custom behavior goes into the Codable implementation of this ABV type.

Struct Beer then looks like:

struct Beer: Codable {
    let name: String
    let abv: ABV
    …
}

ABV can have API on it to get the numeric value or String value; or that could go into Beer and it would abstract the ABV type from callers.

- Tony

On Aug 30, 2017, at 2:42 PM, Sneed, Brandon <brsneed@ebay.com <mailto:brsneed@ebay.com>> wrote:

Thanks Youming,

That’s not quite what I meant. I may have misinterpreted what Tony was saying though.

I wanted to do conversion on String, not the containing type. The problem of doing it on the containing type is that as soon as you need one field to be custom, you’re roped into handling all the others. For a small struct, not a big deal, for larger ones, it is. Something like this is what I tried:

import Cocoa

let jsonString = "{" +
    "\"name\": \"Endeavor\"," +
    "\"abv\": 8.9," +
    "\"brewery\": \"Saint Arnold\"," +
    "\"style\": \"ipa\"}"

struct Beer: Codable {
    let name: String
    let abv: String
    let brewery: String
    let style: String
}

extension String {
    init(from decoder: Decoder) throws {
        print("i got hit.")
        let value = try decoder.singleValueContainer().decode(String.self)
        self.init(value)
    }
}

let jsonData = jsonString.data(using: .utf8)
let decoder = JSONDecoder()
let beer = try! decoder.decode(Beer.self, from: jsonData!)

fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [__lldb_expr_17.Beer.(CodingKeys in _C8902E33F84CE6946081129DAF1824E1).abv], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil)): file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.59/src/swift/stdlib/public/core/ErrorType.swift, line 181

From: Youming Lin <ylin@us.ibm.com <mailto:ylin@us.ibm.com>>
Date: Wednesday, August 30, 2017 at 2:35 PM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Brandon

I cooked up a simple example and it works as expected.

ylin@youming-mbpr:~/Swift/Configuration$ swift
Welcome to Apple Swift version 4.0-dev (LLVM 2dedb62a0b, Clang b9d76a314c, Swift 0899bd328a). Type :help for assistance.
1> import Foundation
2> struct A: Codable {
3. var integer: Int
4.
5. public init(integer: Int) {
6. self.integer = integer
7. }
8.
9. public init(from decoder: Decoder) throws {
10. print("Custom decoder")
11. let container = try decoder.container(keyedBy: CodingKeys.self)
12. integer = try container.decode(Int.self, forKey: .integer)
13. }
14. }
15.
16. try! JSONDecoder().decode(A.self, from: JSONEncoder().encode(A(integer: 42)))
Custom decoder
$R0: A = {
integer = 42
}

You should be able to implement your custom init to convert the number into a string and JSONDecoder should use that automatically.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

<image001.gif>"Sneed, Brandon" ---08/30/2017 04:14:57 PM---Thanks Youming, Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually

From: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
To: Youming Lin <ylin@us.ibm.com <mailto:ylin@us.ibm.com>>
Cc: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>>
Date: 08/30/2017 04:14 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Thanks Youming,

Ok, thanks! I did try that, but I can’t seem to figure out how to make it actually get used in the decoding process. That being my preferred way, I tried it first. I chalked it not working up to Swift not knowing which of the 2 init(from decoder:) functions to call, mine or theirs. But, maybe there’s something I’m missing here.

Any insight is appreciated.

Thanks!

Brandon Sneed

From: Youming Lin <ylin@us.ibm.com <mailto:ylin@us.ibm.com>>
Date: Wednesday, August 30, 2017 at 1:18 PM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>, "swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>" <swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Brandon

>JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance.

You can override the default behavior with your own custom init(from:) implementation for your Codable struct: https://developer.apple.com/documentation/swift/decodable/2894081-init <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Fdeveloper.apple.com-252Fdocumentation-252Fswift-252Fdecodable-252F2894081-2Dinit-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DoLr1Q10-252BztzwG-252BCXpMinBzJNTwSy-252FjoBsKm9Glg1-252FxY-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3Dh1azblXptqRwHqDQhejN9sSFa8dR-Gd8OkB7_6VwgNg%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=TIZrCfocLCJGcfOj%2B9V2FEiXPSTKN4hnL1Rm03GqHvk%3D&reserved=0&gt;

You can check Foundation source code (i.e., the URL struct) on how this can be implemented.

Thanks,

Youming Lin
IBM Cloud, Swift@IBM, Kitura developer
Austin, TX
GitHub: @youming-lin

<image002.gif>"Sneed, Brandon via swift-corelibs-dev" ---08/30/2017 03:07:05 PM---Hi Tony, I like the idea that the type itself is responsible for the conversion. My own json encode

From: "Sneed, Brandon via swift-corelibs-dev" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
To: Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>
Cc: "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
Date: 08/30/2017 03:07 PM
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode
Sent by: swift-corelibs-dev-bounces@swift.org <mailto:swift-corelibs-dev-bounces@swift.org>

Hi Tony,

I like the idea that the type itself is responsible for the conversion. My own json encode/decode library worked this way and it was really great, however in trying to leverage Swift4 into it, or to replace it, I just don’t see how that’s possible given how it’s currently structured.

JSON’s types effectively end up matching specifically to primitives, of which there is no mechanism to override the behavior of how a String gets decoded for instance. The only way I can think of to accomplish that is to create *another* type, JSONString for example, but since String is a struct, I can’t subclass it, and instead need to have the real value buried inside of it … it seems to start getting messy very quickly. It also adds the obfuscation of dealing with yet another type, which I’m not against, but just feels less than ideal.

Brandon Sneed

From: <anthony.parker@apple.com <mailto:anthony.parker@apple.com>> on behalf of Tony Parker <anthony.parker@apple.com <mailto:anthony.parker@apple.com>>
Date: Wednesday, August 30, 2017 at 11:30 AM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: Itai Ferber <iferber@apple.com <mailto:iferber@apple.com>>, "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

I’m still not convinced that we should actually provide such a strategy.

Conversions like those below seem like the domain of each type that is being decoded. If, in a particular type, the “number” can be either a true number or a string, then that type can try decoding it as one or the other and fall back as required. That puts the responsibility of doing that kind of conversion in the type itself.

JSON has very few types already. I’m not sure we want to blur the line between numbers and strings automatically…

- Tony
On Aug 30, 2017, at 11:24 AM, Sneed, Brandon via swift-corelibs-dev <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>> wrote:

Hi Itai,

No problem! Thanks for the heads up. Is there any way I could be involved? Happy to do the work to whatever guidance your team might have. I’m mostly just interested in it being there soon, hence volunteering.

Thanks!

Brandon Sneed

From: <iferber@apple.com <mailto:iferber@apple.com>> on behalf of Itai Ferber <iferber@apple.com <mailto:iferber@apple.com>>
Date: Wednesday, August 30, 2017 at 11:22 AM
To: "Sneed, Brandon" <brsneed@ebay.com <mailto:brsneed@ebay.com>>
Cc: "swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>" <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Hi Brandon,
Thanks for looking at this! We’ve got plans internally to potentially add a strategy to JSONEncoder/JSONDecoder to allow lenient conversions like this — i.e. implicitly stringify numbers (or parse them from string input), among some others.
This would be opt-in for consumers of JSONDecoder while not requiring any special annotations on Codable types.
— Itai
On 30 Aug 2017, at 10:59, Sneed, Brandon via swift-corelibs-dev wrote:
Hi everyone,

Just throwing this out to see if anyone else is working on this, or has opinions/suggestions on how it’s implemented. I’d like to add this to the Codable/JSONDecoder/JSONEncoder system if no one else is working on it.

Type type conversion, I mean given this JSON payload:

{
"name": "Endeavor”,
"abv": 8.9,
"brewery": "Saint Arnold”,
"style": "ipa"
}

and a struct defined as:

struct Beer: Codable {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

Notice that “abv” is a number in the JSON, but a String in the struct. I’d like to make it such that I can let the system know it’s ok to convert it from a number to a string as opposed to throwing an exception. The benefits are:

1. It’s defensive; service types can change without causing my application to crash.
2. It allows a developer to work with the types they want to work with as opposed to what the server provides, thus saving them time of writing a custom encode/decode code for all members.

The argument against it that I’ve heard is generally “it’s a service bug, make them fix it”, which is valid but the reality is we’re not all in control of the services we injest. The same type of logic could be applied to a member name changing, though I haven’t seen this happen often in practice. I do see types in a json payload change with some frequency though. I think much of the reason stems from the fact that type conversion in javascript is effectively free, ie: you ask for a String, you get a String if possible.

To implement this type conversion in practice, looking at it from the point of view using Codable/JSON(en/de)coder, one way would be to make it opt-in:

struct Beer: Codable, CodingConvertible {
let name: String
let abv: String
let brewery: String
let style: BeerStyle
}

I like this because looking at the struct, the members still remain clear and relatively unambiguous. The downside is it’s unknown which member is likely to get converted. And since it’s opt-in, conversion doesn’t happen if the CodingConvertible conformance isn’t adhered to.

Another option would be to box each type, like so:

struct Beer: Codable {
let name: String
let abv: Convertible<String>
let brewery: String
let style: BeerStyle
}

This seems tedious for developers, but would show which types are being converted. It does however seriously weaken benefit #1 above.

Those example usages above aside, I do think it’d be best if this conversion behavior was the default and no end-developer changes required. I think that could be done without impact to code that’s been already been written against the JSON en/decode bits.

I’m very open to alternatives, other ideas, or anything else you might have to say on the subject. Thanks for reading!

Brandon Sneed

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C0e58a975be44418826d608d4efd427dc-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397141865218008-26sdata-3DytYIqDtMesw4NnpUbFmiWF2-252FKfxlawG4YuVWPJd099Y-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DrVZl8iT3jj1nzuDTCqZ1pkhQIZD3-Byi8PUj50swTUg%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=GkxX7xyhtHr1zqISNmjeBhvOkVoZdOihXcaugXSK9tA%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Flists.swift.org-252Fmailman-252Flistinfo-252Fswift-2Dcorelibs-2Ddev-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257Cf2eba37a5b40474e09b108d4efd5372d-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397146413883032-26sdata-3DC1-252F8MXq-252Fh7NHgyxeKDkcHDcigtQjSztCaAeUxBzYZ3g-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3DViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg%26s%3DLQ0cgWtC9rXRTDLu0W58VIukWrsRssHsIMGb9U6Y0MU%26e%3D&data=02|01|brsneed%40ebay.com|6290a819253b47b0eb2408d4efe454ae|46326bff992841a0baca17c16c94ea99|0|0|636397211330551372&sdata=afQLw7%2FVip%2Bts1P60ALOHrTNap93519tWLjYzkS2o5Q%3D&reserved=0&gt;
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.swift.org_mailman_listinfo_swift-2Dcorelibs-2Ddev&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=gkRZBtsmKeGPCOlAIRJoOA&m=ViDSVPImta3StTVAcktby2PMF_-du5itzz47jo-tNHg&s=zRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-ot9_pwAgqI&e= <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefense.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-3A__na01.safelinks.protection.outlook.com_-3Furl-3Dhttps-253A-252F-252Furldefense.proofpoint.com-252Fv2-252Furl-253Fu-253Dhttps-2D3A-5F-5Flists.swift.org-5Fmailman-5Flistinfo-5Fswift-2D2Dcorelibs-2D2Ddev-2526d-253DDwIGaQ-2526c-253Djf-5FiaSHvJObTbx-2DsiA1ZOg-2526r-253DgkRZBtsmKeGPCOlAIRJoOA-2526m-253DViDSVPImta3StTVAcktby2PMF-5F-2Ddu5itzz47jo-2DtNHg-2526s-253DzRuNQ3NLxpfhFBewRTkoMWZnpvHlm6Ja-2Dot9-5FpwAgqI-2526e-253D-26data-3D02-257C01-257Cbrsneed-2540ebay.com-257C6290a819253b47b0eb2408d4efe454ae-257C46326bff992841a0baca17c16c94ea99-257C0-257C0-257C636397211330551372-26sdata-3DkUgv-252B3QRVpUH5JGBclTqYHheS-252FfaDPIWTrTk-252F-252BX8J-252Bs-253D-26reserved-3D0%26d%3DDwMGaQ%26c%3Djf_iaSHvJObTbx-siA1ZOg%26r%3DgkRZBtsmKeGPCOlAIRJoOA%26m%3Dc3lYikOfd2-4q_nd_qMnJ4gXKIuKuxxoJRxIrIZc3Hw%26s%3DlhWK6MIAPUmU4rsIhtD7P7EgacPwfGk17SvpQdMJogc%26e%3D&data=02|01|brsneed%40ebay.com|ebd9669255614ce4dccc08d4efef218c|46326bff992841a0baca17c16c94ea99|0|0|636397257717072726&sdata=jJucdx3j9pb2ylcsHYaVAtze%2B%2BQWr%2F%2Bm2GpBRlHaBTk%3D&reserved=0&gt;

Yeah, I don’t know about the “many types” part. But essentially, if you’re a service developer, you’ll probably have at least 3 clients. Web, Android and iOS. Javascript does this conversion transparently, GSON also does this conversion. iOS ends up being the odd man out in this case.

This is entirely me trying to put myself in the service developers shoes… but if I come up with an API contract, that will typically consist of endpoint, overall structure and namin. I can imagine type may fall off my radar given that javascript (the platform I wrote my service in) hides types from me. Using that example at a larger company, the “hey you broke me by changing the type!” scream is followed with “it works fine on web and android”, which in turn causes me to rev the iOS app and wait for people to update.

If it failed on all 3, they’d likely fix/rever the service to avoid having *all* clients broken.

Brandon Sneed

···

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 3:22 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Youming Lin <ylin@us.ibm.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

On Aug 30, 2017, at 3:12 PM, Sneed, Brandon <brsneed@ebay.com<mailto:brsneed@ebay.com>> wrote:

Thanks Tony,

Ah. That should work, and covers benefit #2 I mentioned very nicely. Only downside is that as a developer on an app I may not expect that type to change on the server side so I wouldn’t do it by default, and when it does happen, I then need to apply it to each of its siblings because if it can happen to one, it can happen to the others.

In this case, the server decides to send a String instead of a numeric value for many kinds of types?

I understand that some JSON libraries have options to stringify all numeric values in an attempt to preserve ‘exactness’, although I would argue that this depends on what you do with the numeric value on the other side…

- Tony

Just a quick follow up on that last reply…

As dumpy of an excuse as that is (doing it because the other 2 big platforms do it) when we’re talking about some tech that is very cross platform, I think it’s worth considering.

Brandon Sneed

···

From: <swift-corelibs-dev-bounces@swift.org> on behalf of "Sneed, Brandon via swift-corelibs-dev" <swift-corelibs-dev@swift.org>
Reply-To: "Sneed, Brandon" <brsneed@ebay.com>
Date: Wednesday, August 30, 2017 at 3:29 PM
To: Tony Parker <anthony.parker@apple.com>
Cc: "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

Yeah, I don’t know about the “many types” part. But essentially, if you’re a service developer, you’ll probably have at least 3 clients. Web, Android and iOS. Javascript does this conversion transparently, GSON also does this conversion. iOS ends up being the odd man out in this case.

This is entirely me trying to put myself in the service developers shoes… but if I come up with an API contract, that will typically consist of endpoint, overall structure and namin. I can imagine type may fall off my radar given that javascript (the platform I wrote my service in) hides types from me. Using that example at a larger company, the “hey you broke me by changing the type!” scream is followed with “it works fine on web and android”, which in turn causes me to rev the iOS app and wait for people to update.

If it failed on all 3, they’d likely fix/rever the service to avoid having *all* clients broken.

Brandon Sneed

From: <anthony.parker@apple.com> on behalf of Tony Parker <anthony.parker@apple.com>
Date: Wednesday, August 30, 2017 at 3:22 PM
To: "Sneed, Brandon" <brsneed@ebay.com>
Cc: Youming Lin <ylin@us.ibm.com>, "swift-corelibs-dev@swift.org" <swift-corelibs-dev@swift.org>
Subject: Re: [swift-corelibs-dev] Adding type conversion capabilities to JSON encode/decode

On Aug 30, 2017, at 3:12 PM, Sneed, Brandon <brsneed@ebay.com<mailto:brsneed@ebay.com>> wrote:

Thanks Tony,

Ah. That should work, and covers benefit #2 I mentioned very nicely. Only downside is that as a developer on an app I may not expect that type to change on the server side so I wouldn’t do it by default, and when it does happen, I then need to apply it to each of its siblings because if it can happen to one, it can happen to the others.

In this case, the server decides to send a String instead of a numeric value for many kinds of types?

I understand that some JSON libraries have options to stringify all numeric values in an attempt to preserve ‘exactness’, although I would argue that this depends on what you do with the numeric value on the other side…

- Tony

I couldn't wait and just created this for our project. I added LeniencyStrategy ( strict or lenient, defaults to strict) and added it as an option to the JSONDecoderImpl then added functionality in the JSONDecoderImpl where it would apply.

Can I go ahead and submit a PR for this or is it in progress?

It would have been so much cleaner if I could have extended JSONDecoderImpl and just added the few extended functions I needed but it's set to file private.