<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">My apologies. I misstated the problem: I don’t want to just limit to Int, String, [Int], etc. but also allow structures where<div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>struct NewThingy : Codable {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>let data1: T1</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>let data2: T2</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><br class=""></div><div class="">where T1 and T2 are themselves Codable.</div><div class=""><br class=""></div><div class="">So basically, back to wanting to let the compiler do the work, when I make new structures, while still allowing for heterogenous containers.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Begin forwarded message:</div><br class="Apple-interchange-newline"><blockquote type="cite" class=""><p style="margin: 0.0px 0.0px 0.0px 40.8px; text-indent: -40.8px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">From: Itai Ferber <<a href="mailto:iferber@apple.com" class="">iferber@apple.com</a>></font></p>
<p style="margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">Subject: Re: [swift-users] dealing with heterogenous lists/dictionary with Codable</font></p>
<p style="margin: 0.0px 0.0px 0.0px 38.1px; text-indent: -38.1px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">Date: October 19, 2017 at 10:40:28 AM PDT</font></p>
<p style="margin: 0.0px 0.0px 0.0px 23.6px; text-indent: -23.6px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">To: David Baraff <<a href="mailto:davidbaraff@gmail.com" class="">davidbaraff@gmail.com</a>></font></p>
<p style="margin: 0.0px 0.0px 0.0px 25.4px; text-indent: -25.4px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">Cc: Geordie Jay <<a href="mailto:geojay@gmail.com" class="">geojay@gmail.com</a>>, swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>></font></p>
<p style="margin: 0.0px 0.0px 0.0px 0.0px; min-height: 14.0px" class=""><br class=""></p>
</blockquote><blockquote type="cite" class="">
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8" class="">
<div style="font-family:sans-serif" class=""><div style="white-space:normal" class="">
<p dir="auto" class="">Why are you stuck? I think the following matches your needs, no?</p>
<pre style="background-color:#F7F7F7; border-radius:5px 5px 5px 5px; margin-left:15px; margin-right:15px; max-width:90vw; overflow-x:auto; padding:5px; color:black" bgcolor="#F7F7F7" class=""><code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0" bgcolor="#F7F7F7" class=""><span style="color: #008800; font-weight: bold" class="">import</span> <span style="color: #BB0066; font-weight: bold" class="">Foundation</span>
<span style="color: #008800; font-weight: bold" class="">enum</span> <span style="color: #BB0066; font-weight: bold" class="">MyType</span> : Codable, <span style="color: #007020" class="">Equatable</span> {
<span style="color: #008800; font-weight: bold" class="">case</span> int(<span style="color: #007020" class="">Int</span>)
<span style="color: #008800; font-weight: bold" class="">case</span> string(<span style="color: #007020" class="">String</span>)
<span style="color: #008800; font-weight: bold" class="">case</span> list([MyType])
<span style="color: #008800; font-weight: bold" class="">case</span> dictionary([<span style="color: #007020" class="">String</span> : MyType])
<span style="color: #008800; font-weight: bold" class="">public</span> <span style="color: #008800; font-weight: bold" class="">init</span>(from decoder: Decoder) throws {
<span style="color: #888888" class="">// Can be made prettier, but as a simple example:</span>
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">container</span> = try decoder.singleValueContainer()
<span style="color: #008800; font-weight: bold" class="">do</span> {
<span style="color: #008800; font-weight: bold" class="">self</span> = .int(try container.decode(<span style="color: #007020" class="">Int</span>.<span style="color: #008800; font-weight: bold" class="">self</span>))
} catch DecodingError.typeMismatch {
<span style="color: #008800; font-weight: bold" class="">do</span> {
<span style="color: #008800; font-weight: bold" class="">self</span> = .string(try container.decode(<span style="color: #007020" class="">String</span>.<span style="color: #008800; font-weight: bold" class="">self</span>))
} catch DecodingError.typeMismatch {
<span style="color: #008800; font-weight: bold" class="">do</span> {
<span style="color: #008800; font-weight: bold" class="">self</span> = .list(try container.decode([MyType].<span style="color: #008800; font-weight: bold" class="">self</span>))
} catch DecodingError.typeMismatch {
<span style="color: #008800; font-weight: bold" class="">self</span> = .dictionary(try container.decode([<span style="color: #007020" class="">String</span> : MyType].<span style="color: #008800; font-weight: bold" class="">self</span>))
}
}
}
}
<span style="color: #008800; font-weight: bold" class="">public</span> <span style="color: #008800; font-weight: bold" class="">func</span> <span style="color: #0066BB; font-weight: bold" class="">encode</span>(to encoder: Encoder) throws {
<span style="color: #008800; font-weight: bold" class="">var</span> <span style="color: #996633" class="">container</span> = encoder.singleValueContainer()
<span style="color: #008800; font-weight: bold" class="">switch</span> <span style="color: #008800; font-weight: bold" class="">self</span> {
<span style="color: #008800; font-weight: bold" class="">case</span> .int(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">int</span>): try container.encode(int)
<span style="color: #008800; font-weight: bold" class="">case</span> .string(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">string</span>): try container.encode(string)
<span style="color: #008800; font-weight: bold" class="">case</span> .list(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">list</span>): try container.encode(list)
<span style="color: #008800; font-weight: bold" class="">case</span> .dictionary(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">dictionary</span>): try container.encode(dictionary)
}
}
<span style="color: #008800; font-weight: bold" class="">static</span> <span style="color: #008800; font-weight: bold" class="">func</span> ==(<span style="color: #008800; font-weight: bold" class="">_</span> lhs: MyType, <span style="color: #008800; font-weight: bold" class="">_</span> rhs: MyType) -> <span style="color: #007020" class="">Bool</span> {
<span style="color: #008800; font-weight: bold" class="">switch</span> (lhs, rhs) {
<span style="color: #008800; font-weight: bold" class="">case</span> (.int(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">int1</span>), .int(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">int2</span>)): <span style="color: #008800; font-weight: bold" class="">return</span> int1 == int2
<span style="color: #008800; font-weight: bold" class="">case</span> (.string(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">string1</span>), .string(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">string2</span>)): <span style="color: #008800; font-weight: bold" class="">return</span> string1 == string2
<span style="color: #008800; font-weight: bold" class="">case</span> (.list(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">list1</span>), .list(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">list2</span>)): <span style="color: #008800; font-weight: bold" class="">return</span> list1 == list2
<span style="color: #008800; font-weight: bold" class="">case</span> (.dictionary(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">dict1</span>), .dictionary(<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">dict2</span>)): <span style="color: #008800; font-weight: bold" class="">return</span> dict1 == dict2
<span style="color: #008800; font-weight: bold" class="">default</span>: <span style="color: #008800; font-weight: bold" class="">return</span> <span style="color: #008800; font-weight: bold" class="">false</span>
}
}
}
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">values</span>: MyType = .list([.int(<span style="color: #0000DD; font-weight: bold" class="">42</span>), .string(<span style="background-color: #fff0f0" class="">"hello!"</span>), .list([.int(<span style="color: #0000DD; font-weight: bold" class="">9</span>), .string(<span style="background-color: #fff0f0" class="">"hi"</span>)]), .dictionary([<span style="background-color: #fff0f0" class="">"zero"</span>: .int(<span style="color: #0000DD; font-weight: bold" class="">0</span>), <span style="background-color: #fff0f0" class="">"one"</span>: .int(<span style="color: #0000DD; font-weight: bold" class="">1</span>)])])
<span style="color: #007020" class="">print</span>(values)
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">encoder</span> = JSONEncoder()
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">data</span> = try encoder.encode(values)
<span style="color: #007020" class="">print</span>(<span style="color: #007020" class="">String</span>(data: data, encoding: .utf8)<span style="color: #333333" class="">!</span>) <span style="color: #888888" class="">// => [42,"hello!",[9,"hi"],{"zero":0,"one":1}]</span>
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">decoder</span> = JSONDecoder()
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">decoded</span> = try decoder.decode(MyType.<span style="color: #008800; font-weight: bold" class="">self</span>, from: data)
<span style="color: #007020" class="">print</span>(decoded)
<span style="color: #007020" class="">print</span>(values == decoded) <span style="color: #888888" class="">// => true</span>
</code></pre>
<p dir="auto" class="">On 19 Oct 2017, at 20:15, David Baraff wrote:</p>
</div>
<div style="white-space:normal" class=""></div>
<blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class=""><div id="1E73AB49-E90F-4A14-90C5-4EE21DA2889D" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Begin forwarded message:</div><br class="Apple-interchange-newline"><blockquote type="cite" class=""><p style="margin: 0.0px 0.0px 0.0px 40.8px; text-indent: -40.8px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">From: Itai Ferber <<a href="mailto:iferber@apple.com" class="">iferber@apple.com</a>></font></p>
<p style="margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">Subject: Re: [swift-users] dealing with heterogenous lists/dictionary with Codable</font></p>
<p style="margin: 0.0px 0.0px 0.0px 38.1px; text-indent: -38.1px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">Date: October 19, 2017 at 9:39:25 AM PDT</font></p>
<p style="margin: 0.0px 0.0px 0.0px 23.6px; text-indent: -23.6px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">To: David Baraff <<a href="mailto:davidbaraff@gmail.com" class="">davidbaraff@gmail.com</a>></font></p>
<p style="margin: 0.0px 0.0px 0.0px 25.4px; text-indent: -25.4px" class=""><font face=".AppleSystemUIFont" size="4" color="#000000" style="font: 14.0px '.AppleSystemUIFont'; color: #000000" class="">Cc: Geordie Jay <<a href="mailto:geojay@gmail.com" class="">geojay@gmail.com</a>>, swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>></font></p>
<p style="margin: 0.0px 0.0px 0.0px 0.0px; min-height: 14.0px" class=""><br class=""></p>
</blockquote><blockquote type="cite" class="">
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8" class="">
<div style="font-family:sans-serif" class=""><div style="white-space:normal" class="">
<p dir="auto" class="">Hi David and Geordie,</p>
<p dir="auto" class="">That approach won’t work — encoders and decoders only work directly with concrete <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">Codable</code> types (e.g. <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">String</code>, <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">Int</code>, <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">MyFoo</code> [where <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">MyFoo</code> is <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">Codable], etc.).<br class="">
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 general</code>Codable` isn’t helpful.</p>
<p dir="auto" class="">Since it’s unlikely that what you truly need is a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">[String : Any]</code> but really a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">[String : <one of String, Int, MyFoo, etc.>]</code>, one easy way to decode this type is to create a wrapper <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">enum</code> or similar which overrides <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">init(from:)</code> to be able to decode from one of those types. You can then ask to decode a <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">[String : MyWrapperType]</code> and use that instead.</p>
<p dir="auto" class="">What types are you expecting in the dictionary?</p><div class=""><br class=""></div></div></div></blockquote><div class=""><br class=""></div>The problem is that I want to be able to encode types T where<div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>(a) T is String, Int</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>(b) lists of T</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>(c ) dictionaries of type <String, T></div><div class=""><br class=""></div><div class="">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.).</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Let’s turn this around: in addition to the JSONEncoder, one can also use the PropertyListEncoder. </div><div class=""><br class=""></div><div class="">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?</div><div class=""><br class=""></div><div class="">I really do want a heterogenous container. I think I am stuck.</div><div class=""><br class=""><blockquote type="cite" class=""><div style="font-family:sans-serif" class=""><div style="white-space:normal" class="">
<p dir="auto" class="">— Itai</p>
<p dir="auto" class="">On 19 Oct 2017, at 18:11, David Baraff via swift-users wrote:</p>
</div>
<div style="white-space:normal" class=""></div>
<blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class=""><div id="3D733C52-04CA-42EA-A993-C0A29520E430" class=""><div dir="auto" class="">I’ll try. Is that cast smart enough to apply recursively? We shall see.<br class=""><br class=""><div class="">Sent from my iPad</div><div class=""><br class="">On Oct 19, 2017, at 7:34 AM, Geordie Jay <<a href="mailto:geojay@gmail.com" class="">geojay@gmail.com</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class=""><div dir="auto" class="">I mean can you do something along the lines of</div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">let codableDict = stringAnyDict as? [String : Codable]</div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">?</div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">I’m not at a computer to test it myself</div><div dir="auto" class=""><br class=""></div><div dir="auto" class=""><br class=""></div><div dir="auto" class=""><br class=""></div><div dir="auto" class=""><br class=""></div><div class="gmail_quote"><div class="">David Baraff <<a href="mailto:davidbaraff@gmail.com" class="">davidbaraff@gmail.com</a>> schrieb am Do. 19. Okt. 2017 um 15:45:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto" class="">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?<div class=""><br class=""><br class=""><div id="m_-5564253180470883141AppleMailSignature" class="">Sent from my iPad</div></div></div><div dir="auto" class=""><div class=""><div class=""><br class="">On Oct 19, 2017, at 3:38 AM, Geordie Jay <<a href="mailto:geojay@gmail.com" target="_blank" class="">geojay@gmail.com</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class=""><br class=""><div class="gmail_quote"><div dir="auto" class="">David Baraff via swift-users <<a href="mailto:swift-users@swift.org" target="_blank" class="">swift-users@swift.org</a>> schrieb am Do. 19. Okt. 2017 um 03:47:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">So I have simple structs like this:<br class="">
<br class="">
struct Library: Codable {<br class="">
let domain: String<br class="">
let unit: String<br class="">
}<br class="">
<br class="">
and it’s super-simple to serialize. Yay.<br class="">
<br class="">
But:<br class="">
<br class="">
struct LibraryGroup : Codable { // I wish...<br class="">
let libraries: [Library]<br class="">
let someDict: [String : Any]<br class="">
}<br class="">
</blockquote><div dir="auto" class=""><br class=""></div><div dir="auto" class="">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?</div><div dir="auto" class=""><br class=""></div><div dir="auto" class="">Geordie</div><div dir="auto" class=""><br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br class="">
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.<br class="">
<br class="">
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?<br class="">
<br class="">
Is my only alternative to write a custom coder for LibraryGroup? Is there any hope I could teach Codable what to do with<br class="">
[String: Any]<br class="">
<br class="">
?<br class="">
<br class="">
<br class="">
_______________________________________________<br class="">
swift-users mailing list<br class="">
<a href="mailto:swift-users@swift.org" target="_blank" class="">swift-users@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-users</a><br class="">
</blockquote></div></div>
</div></blockquote></div></div></blockquote></div></div>
</div></blockquote></div></div></blockquote>
<div style="white-space:normal" class="">
<blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class="">
</blockquote><blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class=""><p dir="auto" class="">_______________________________________________<br class="">
swift-users mailing list<br class="">
<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-users" style="color:#777" class="">https://lists.swift.org/mailman/listinfo/swift-users</a></p>
</blockquote></div>
<div style="white-space:normal" class="">
</div>
</div>
</blockquote></div></div></div></blockquote>
<div style="white-space:normal" class="">
<blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class="">
</blockquote></div>
<div style="white-space:normal" class="">
</div>
</div>
</blockquote></div></body></html>