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

Reply via email to