> On Aug 30, 2017, at 3:12 PM, Sneed, Brandon <brsn...@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 > > 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.par...@apple.com> on behalf of Tony Parker > <anthony.par...@apple.com> > Date: Wednesday, August 30, 2017 at 3:04 PM > To: "Sneed, Brandon" <brsn...@ebay.com> > Cc: Youming Lin <y...@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 <brsn...@ebay.com > <mailto:brsn...@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 <y...@us.ibm.com <mailto:y...@us.ibm.com>> > Date: Wednesday, August 30, 2017 at 2:35 PM > To: "Sneed, Brandon" <brsn...@ebay.com <mailto:brsn...@ebay.com>> > Cc: Tony Parker <anthony.par...@apple.com <mailto:anthony.par...@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-boun...@swift.org > <mailto:swift-corelibs-dev-boun...@swift.org>" > <swift-corelibs-dev-boun...@swift.org > <mailto:swift-corelibs-dev-boun...@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" <brsn...@ebay.com <mailto:brsn...@ebay.com>> > To: Youming Lin <y...@us.ibm.com <mailto:y...@us.ibm.com>> > Cc: Tony Parker <anthony.par...@apple.com <mailto:anthony.par...@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-boun...@swift.org > <mailto:swift-corelibs-dev-boun...@swift.org>" > <swift-corelibs-dev-boun...@swift.org > <mailto:swift-corelibs-dev-boun...@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 <y...@us.ibm.com <mailto:y...@us.ibm.com>> > Date: Wednesday, August 30, 2017 at 1:18 PM > To: "Sneed, Brandon" <brsn...@ebay.com <mailto:brsn...@ebay.com>> > Cc: Tony Parker <anthony.par...@apple.com <mailto:anthony.par...@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-boun...@swift.org > <mailto:swift-corelibs-dev-boun...@swift.org>" > <swift-corelibs-dev-boun...@swift.org > <mailto:swift-corelibs-dev-boun...@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%7C01%7Cbrsneed%40ebay.com%7Cebd9669255614ce4dccc08d4efef218c%7C46326bff992841a0baca17c16c94ea99%7C0%7C0%7C636397257717072726&sdata=TIZrCfocLCJGcfOj%2B9V2FEiXPSTKN4hnL1Rm03GqHvk%3D&reserved=0> > > 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.par...@apple.com <mailto:anthony.par...@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-boun...@swift.org > <mailto:swift-corelibs-dev-boun...@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.par...@apple.com <mailto:anthony.par...@apple.com>> on behalf > of Tony Parker <anthony.par...@apple.com <mailto:anthony.par...@apple.com>> > Date: Wednesday, August 30, 2017 at 11:30 AM > To: "Sneed, Brandon" <brsn...@ebay.com <mailto:brsn...@ebay.com>> > Cc: Itai Ferber <ifer...@apple.com <mailto:ifer...@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: <ifer...@apple.com <mailto:ifer...@apple.com>> on behalf of Itai Ferber > <ifer...@apple.com <mailto:ifer...@apple.com>> > Date: Wednesday, August 30, 2017 at 11:22 AM > To: "Sneed, Brandon" <brsn...@ebay.com <mailto:brsn...@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%7C01%7Cbrsneed%40ebay.com%7C6290a819253b47b0eb2408d4efe454ae%7C46326bff992841a0baca17c16c94ea99%7C0%7C0%7C636397211330551372&sdata=GkxX7xyhtHr1zqISNmjeBhvOkVoZdOihXcaugXSK9tA%3D&reserved=0> > _______________________________________________ > 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%7C01%7Cbrsneed%40ebay.com%7C6290a819253b47b0eb2408d4efe454ae%7C46326bff992841a0baca17c16c94ea99%7C0%7C0%7C636397211330551372&sdata=afQLw7%2FVip%2Bts1P60ALOHrTNap93519tWLjYzkS2o5Q%3D&reserved=0> > _______________________________________________ > 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%7C01%7Cbrsneed%40ebay.com%7Cebd9669255614ce4dccc08d4efef218c%7C46326bff992841a0baca17c16c94ea99%7C0%7C0%7C636397257717072726&sdata=jJucdx3j9pb2ylcsHYaVAtze%2B%2BQWr%2F%2Bm2GpBRlHaBTk%3D&reserved=0> > > > > > > > > > >
_______________________________________________ swift-corelibs-dev mailing list swift-corelibs-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-corelibs-dev