> 
> 
> 
> 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.
> 
> That’s strange.

I don’t think it is.  I would completely expect Swift to handle a dictionary of 
a concrete type: that’s not a heteregenous container then.  When you use the 
protocol Codable, then it becomes heterogenous, which is the issue.


> We’re actually doing exactly this and it works for us (although we are using 
> a concrete Codable type rather than the Codable metatype itself).
> 
> Maybe it’s worth filing a bug on Jira
> 
> Good luck.
> 
> 
>> 
>> 
>> 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