Begin forwarded message:
> From: Geordie Jay <geo...@gmail.com> > Subject: Re: [swift-users] dealing with heterogenous lists/dictionary with > Codable > Date: October 19, 2017 at 12:24:44 PM PDT > To: David Baraff <davidbar...@gmail.com>, Itai Ferber <ifer...@apple.com> > Cc: swift-users <swift-users@swift.org> > > > > David Baraff <davidbar...@gmail.com <mailto:davidbar...@gmail.com>> schrieb > am Do. 19. Okt. 2017 um 21:14: > My apologies. I misstated the problem: I don’t want to just limit to Int, > String, [Int], etc. but also allow structures where > > struct NewThingy : Codable { > let data1: T1 > let data2: T2 > } > > where T1 and T2 are themselves Codable. > > This is already possible, just not with dictionaries of unknown types > (because they’re not known to be Codable) Sure, but I don’t want to give a dictionary of unknown types: i’m very happy to say that my dictionary is [String : Codable] but struct Foo : Codable { let d: [String : Codable] } doesn’t work; the d inside F is not itself Codable. > > > So basically, back to wanting to let the compiler do the work, when I make > new structures, while still allowing for heterogenous containers. > > It’s also possible to give the compiler hints as to what decodes into what. > Have you looked at the docs on the Apple foundation page? > > https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types > > <https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types> > > Geordie > > > > > > > > > Begin forwarded message: > > >> From: Itai Ferber <ifer...@apple.com <mailto:ifer...@apple.com>> >> Subject: Re: [swift-users] dealing with heterogenous lists/dictionary with >> Codable > >> Date: October 19, 2017 at 10:40:28 AM PDT > >> To: David Baraff <davidbar...@gmail.com <mailto:davidbar...@gmail.com>> >> Cc: Geordie Jay <geo...@gmail.com <mailto:geo...@gmail.com>>, swift-users >> <swift-users@swift.org <mailto:swift-users@swift.org>> >> > >> Why are you stuck? I think the following matches your needs, no? >> >> import Foundation >> >> enum MyType : Codable, Equatable { >> case int(Int) >> case string(String) >> case list([MyType]) >> case dictionary([String : MyType]) >> >> public init(from decoder: Decoder) throws { >> // Can be made prettier, but as a simple example: >> let container = try decoder.singleValueContainer() >> do { >> self = .int(try container.decode(Int.self)) >> } catch DecodingError.typeMismatch { >> do { >> self = .string(try container.decode(String.self)) >> } catch DecodingError.typeMismatch { >> do { >> self = .list(try container.decode([MyType].self)) >> } catch DecodingError.typeMismatch { >> self = .dictionary(try container.decode([String : >> MyType].self)) >> } >> } >> } >> } >> >> public func encode(to encoder: Encoder) throws { >> var container = encoder.singleValueContainer() >> switch self { >> case .int(let int): try container.encode(int) >> case .string(let string): try container.encode(string) >> case .list(let list): try container.encode(list) >> case .dictionary(let dictionary): try container.encode(dictionary) >> } >> } >> >> static func ==(_ lhs: MyType, _ rhs: MyType) -> Bool { >> switch (lhs, rhs) { >> case (.int(let int1), .int(let int2)): return int1 == int2 >> case (.string(let string1), .string(let string2)): return string1 == >> string2 >> case (.list(let list1), .list(let list2)): return list1 == list2 >> case (.dictionary(let dict1), .dictionary(let dict2)): return dict1 >> == dict2 >> default: return false >> } >> } >> } >> >> let values: MyType = .list([.int(42), .string("hello!"), .list([.int(9), >> .string("hi")]), .dictionary(["zero": .int(0), "one": .int(1)])]) >> print(values) >> >> let encoder = JSONEncoder() >> let data = try encoder.encode(values) >> print(String(data: data, encoding: .utf8)!) // => >> [42,"hello!",[9,"hi"],{"zero":0,"one":1}] >> >> let decoder = JSONDecoder() >> let decoded = try decoder.decode(MyType.self, from: data) >> print(decoded) >> >> print(values == decoded) // => true >> On 19 Oct 2017, at 20:15, David Baraff wrote: >> >> Begin forwarded message: >> >>> From: Itai Ferber <ifer...@apple.com <mailto:ifer...@apple.com>> >>> Subject: Re: [swift-users] dealing with heterogenous lists/dictionary with >>> Codable >>> Date: October 19, 2017 at 9:39:25 AM PDT >>> To: David Baraff <davidbar...@gmail.com <mailto:davidbar...@gmail.com>> >>> Cc: Geordie Jay <geo...@gmail.com <mailto:geo...@gmail.com>>, swift-users >>> <swift-users@swift.org <mailto:swift-users@swift.org>> >>> >>> Hi David and Geordie, >>> >>> That approach won’t work — encoders and decoders only work directly with >>> concrete Codable types (e.g. String, Int, MyFoo [where MyFoo is Codable], >>> etc.). >>> This is by design: since there is no type information stored in the JSON >>> payload, there isn’t necessarily a way to tell how to decode the type >>> you’re looking at, so asking for a generalCodable` isn’t helpful. >>> >>> Since it’s unlikely that what you truly need is a [String : Any] but really >>> a [String : <one of String, Int, MyFoo, etc.>], one easy way to decode this >>> type is to create a wrapper enum or similar which overrides init(from:) to >>> be able to decode from one of those types. You can then ask to decode a >>> [String : MyWrapperType] and use that instead. >>> >>> What types are you expecting in the dictionary? >>> >>> >> >> The problem is that I want to be able to encode types T where >> (a) T is String, Int >> (b) lists of T >> (c ) dictionaries of type <String, T> >> >> The problem is the recursive nature: yes, my types are simple (say only base >> types String and Int) but the “nesting” level may be quite deep (a list of >> list of dictionaries of <etc.). >> >> >> Let’s turn this around: in addition to the JSONEncoder, one can also use >> the PropertyListEncoder. >> >> Are we saying that something one could pull from a property list file (which >> is pretty much what i want: arbitrary deep nesting of basic types) is also >> not Codable? So a PropertyListEncoder could not encode actual property >> lists? >> >> I really do want a heterogenous container. I think I am stuck. >> >>> — Itai >>> >>> On 19 Oct 2017, at 18:11, David Baraff via swift-users wrote: >>> >>> I’ll try. Is that cast smart enough to apply recursively? We shall see. >>> >>> Sent from my iPad >>> >>> On Oct 19, 2017, at 7:34 AM, Geordie Jay <geo...@gmail.com >>> <mailto:geo...@gmail.com>> wrote: >>> >>>> I mean can you do something along the lines of >>>> >>>> let codableDict = stringAnyDict as? [String : Codable] >>>> >>>> ? >>>> >>>> I’m not at a computer to test it myself >>>> >>>> >>>> >>>> >>>> David Baraff <davidbar...@gmail.com <mailto:davidbar...@gmail.com>> >>>> schrieb am Do. 19. Okt. 2017 um 15:45: >>>> That’s exactly what I want. The ironic part is that I got my dictionary >>>> by decoding a Json file. If that’s where my dictionary came from, is >>>> there a simple way of coercing the Json serialization routines to give me >>>> back codables, rather than Anys? >>>> >>>> >>>> Sent from my iPad >>>> >>>> On Oct 19, 2017, at 3:38 AM, Geordie Jay <geo...@gmail.com >>>> <mailto:geo...@gmail.com>> wrote: >>>> >>>>> >>>>> David Baraff via swift-users <swift-users@swift.org >>>>> <mailto:swift-users@swift.org>> schrieb am Do. 19. Okt. 2017 um 03:47: >>>>> So I have simple structs like this: >>>>> >>>>> struct Library: Codable { >>>>> let domain: String >>>>> let unit: String >>>>> } >>>>> >>>>> and it’s super-simple to serialize. Yay. >>>>> >>>>> But: >>>>> >>>>> struct LibraryGroup : Codable { // I wish... >>>>> let libraries: [Library] >>>>> let someDict: [String : Any] >>>>> } >>>>> >>>>> I haven’t tried this, but is it possible to have a dictionary of [String >>>>> : Codable] ? Because that’s exactly the type requirements you’re >>>>> describing, no? >>>>> >>>>> Geordie >>>>> >>>>> >>>>> So what I’m looking for is something where if the values in someDict are >>>>> themselves Codable, I can serialize things, and if they’re not, I can’t. >>>>> In my previous scheme, I was using NSKeyedArchiver to serialize >>>>> everything, manualy, including someDict; in trying to switch to Codable I >>>>> ran smack into the fact that Codable wants to know what all the types >>>>> are, in advance. >>>>> >>>>> Am I just stuck? How do I get the best of both worlds, where the >>>>> compiler can make use of the fact that it can see the data types of my >>>>> structures, while still being able to serialize heterogenous data like is >>>>> found in LibraryGroup? >>>>> >>>>> Is my only alternative to write a custom coder for LibraryGroup? Is >>>>> there any hope I could teach Codable what to do with >>>>> [String: Any] >>>>> >>>>> ? >>>>> >>>>> >>>>> _______________________________________________ >>>>> swift-users mailing list >>>>> swift-users@swift.org <mailto:swift-users@swift.org> >>>>> https://lists.swift.org/mailman/listinfo/swift-users >>>>> <https://lists.swift.org/mailman/listinfo/swift-users> >>> >>> _______________________________________________ >>> swift-users mailing list >>> swift-users@swift.org <mailto:swift-users@swift.org> >>> https://lists.swift.org/mailman/listinfo/swift-users >>> <https://lists.swift.org/mailman/listinfo/swift-users> >>
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users