{"id":106692,"date":"2022-05-30T07:00:00","date_gmt":"2022-05-30T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106692"},"modified":"2022-05-28T06:46:55","modified_gmt":"2022-05-28T13:46:55","slug":"20220530-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220530-00\/?p=106692","title":{"rendered":"On passing iterables of iterables in the Windows Runtime"},"content":{"rendered":"<p>The Windows Runtime API design guidelines recommend that methods accept iterables rather than specific collections where possible. This allows clients to pass any iterable collection of their choosing, or possibly no collection at all (like a LINQ query).<\/p>\n<p>The generalization rules are:<\/p>\n<ul>\n<li>Arrays of T are accepted as <code>IIterable&lt;T&gt;<\/code>.<\/li>\n<li>Maps from K to V are accepted as <code>IIterable&lt;IKeyValuePair&lt;K, V&gt;&gt;<\/code>.<\/li>\n<\/ul>\n<p>This works out well in practice because iterable collections support <code>IIterable<\/code>, so you can just pass the collection, and the language projection will pass the <code>IIterable<\/code> to the method.<\/p>\n<p>Things get a little weirder if you want to pass a collection of collections. For example, suppose you have a method which wants to accept an array of maps.<\/p>\n<pre>void Something(IVector&lt;IMap&lt;String, String&gt;&gt; attributesArray);\r\n<\/pre>\n<p>Applying the above guidance means that your method looks like this:<\/p>\n<pre>void Something(IIterable&lt;IIterable&lt;IKeyValuePair&lt;String, String&gt;&gt;&gt; attributesArray);\r\n<\/pre>\n<p>C# supports covariance, but C++ does not. This means that in C#, you can say<\/p>\n<pre>    var v = new[] {\r\n            new Dictionary&lt;string, string&gt; { [\"foo\"] = fooValue },\r\n            new Dictionary&lt;string, string&gt; { [\"bar\"] = barValue },\r\n    };\r\n    var result = Something(v);\r\n<\/pre>\n<p>and the language lets you pass an <code>IEnumerable&lt;Dictionary&lt;string, string&gt;&gt;<\/code> instead of an <code>IEnumerable&lt;IEnumerable&lt;IKeyValuePair&lt;string, string&gt;&gt;&gt;<\/code>.<\/p>\n<p>C++ does not support covariance. If you try the equivalent C++, it fails.<\/p>\n<pre>\/\/ C++\/CX\r\n    using AttributeMap = Map&lt;String^, String^&gt;;\r\n    AttributeMap^ v[2] = {\r\n       ref new AttributeMap{ { \"foo\", fooValue } },\r\n       ref new AttributeMap( { \"bar\", barValue } },\r\n    };\r\n    auto result = Something(v); \/\/ does not compile\r\n\r\n\/\/ C++\/WinRT\r\n    using AttributeMap = IMap&lt;hstring, hstring&gt;;\r\n    AttributeMap v[2] = {\r\n        single_threaded_map(std::map&lt;hstring, hstring&gt;{ { L\"foo\", fooValue } },\r\n        single_threaded_map(std::map&lt;hstring, hstring&gt;{ { L\"bar\", barValue } },\r\n        };\r\n    auto result = Something(v); \/\/ does not compile\r\n<\/pre>\n<p>You have to misdeclare the inner maps as iterables.<\/p>\n<pre>\/\/ C++\/CX\r\n    using AttributeMap = Map&lt;String^, String^&gt;;\r\n    <span style=\"color: blue;\">using IAttributeIterable = Iiterable&lt;IKeyValuePair&lt;String^, String^&gt;&gt;;<\/span>\r\n    auto d1 = ref new AttributeMap{ { \"foo\", fooValue } };\r\n    auto d2 = ref new AttributeMap( { \"bar\", barValue } };\r\n    auto v = ref new Vector&lt;<span style=\"color: blue;\">IAttributeIterable<\/span>&gt;({ d1, d2 });\r\n    auto result = Something(v);\r\n\r\n\/\/ C++\/WinRT\r\n    <span style=\"color: blue;\">using IAttributeIterable = IIterable&lt;IKeyValuePair&lt;hstring, hstring&gt;&gt;;<\/span>\r\n    auto v = std::vector&lt;<span style=\"color: blue;\">IAttributeIterable<\/span>&gt;({\r\n        std::map&lt;hstring, hstring&gt;({ { L\"foo\", fooValue } }),\r\n        std::map&lt;hstring, hstring&gt;({ { L\"bar\", barValue } }),\r\n    });\r\n    auto result = Something(v);\r\n<\/pre>\n<p>Fortunately, C++\/WinRT gives you a bit of help. The <code>winrt::params<\/code> namespace lets you write<\/p>\n<pre>    auto d1 = std::map&lt;hstring, hstring&gt;({ { L\"foo\", fooValue } });\r\n    auto d2 = std::map&lt;hstring, hstring&gt;({ { L\"bar\", barValue } });\r\n    auto result = Something({ d1, d2 });\r\n<\/pre>\n<p>And the appropriate conversions will happen. So C++\/WinRT is roughly on par with C#. C++\/CX is kind of awkward though. Sorry, C++\/CX.<\/p>\n<p><b>Bonus chatter<\/b>: After writing this up, I discovered that I had <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201008-00\/?p=104346\"> already written about it, in a different way<\/a>. So now you have two ways of reading about the same topic.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Different projections help you out in different ways, some more than others.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-106692","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Different projections help you out in different ways, some more than others.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106692","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106692"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106692\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106692"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106692"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106692"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}