{"id":104346,"date":"2020-10-08T07:00:00","date_gmt":"2020-10-08T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104346"},"modified":"2020-10-08T06:26:26","modified_gmt":"2020-10-08T13:26:26","slug":"20201008-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201008-00\/?p=104346","title":{"rendered":"An iterable of iterables: C# collections support covariance, but C++ collections do not"},"content":{"rendered":"<p>Collections in the C# language support covariance. <a href=\"https:\/\/cpptruths.blogspot.com\/2015\/11\/covariance-and-contravariance-in-c.html\"> Collections in the C++ language do not<\/a>.<\/p>\n<p>This means, for example, that if a function wants a collection of <code>T<\/code>, C# lets you pass a collection of things that derive from <code>T<\/code>, but C++ requires you to pass a collection of exactly <code>T<\/code>.<\/p>\n<p>This can be confusing for methods that accept collections of collections. C++ will allow the outer collection to decay, but the objects inside the collection cannot. The Windows Runtime by convention accepts collections of <code>T<\/code> in the form of an <code>IIterable&lt;T&gt;<\/code> (which projects into C# as of an <code>IEnumerable&lt;T&gt;<\/code>), so that you can pass anything that can produce a sequence of <code>T<\/code> objects. It could be a <code>std::vector&lt;T&gt;<\/code> or a <code>std::array&lt;T&gt;<\/code> or even a SQL or LINQ query that produces a sequence of <code>T<\/code> objects.<\/p>\n<p>But things get a little weird if you have a collection of collections, because C++ collections don&#8217;t support covariance.<\/p>\n<p>Before we look at covariance, let&#8217;s look at simple conversion. Suppose you have to pass an <code>IIterable&lt;Point&gt;<\/code> to a method like <code>Ink\u00adManager.<\/code><code>Select\u00adWith\u00adPoly\u00adLine<\/code> which takes a parameter of type <code>IIterable&lt;Point&gt;<\/code>.<\/p>\n<pre>\/\/ C#\r\nvar points = new List&lt;Point&gt; {\r\n        UpperLeftCorner, UpperRightCorner, LowerRightCorner, LowerLeftCorner\r\n    };\r\ninkManager.SelectWithPolyline(points);\r\n\r\n\/\/ C++\/CX\r\nauto points = ref new Vector&lt;Point&gt;({\r\n      UpperLeftCorner, UpperRightCorner, LowerRightCorner, LowerLeftCorner,\r\n});\r\ninkManager-&gt;SelectWithPolyline(points);\r\n\r\n\/\/ C++\/WinRT\r\nauto points = single_threaded_vector&lt;Point&gt;({\r\n      UpperLeftCorner, UpperRightCorner, LowerRightCorner, LowerLeftCorner,\r\n  });\r\ninkManager.SelectWithPolyline(points);\r\n<\/pre>\n<p>This works because <code>List&lt;T&gt;<\/code> is convertible to <code>IEnumerable&lt;T&gt;<\/code>, and <code>Vector&lt;T&gt;<\/code> is convertible to <code>IIterable&lt;T&gt;<\/code>. The conversion works one level deep.<\/p>\n<p>Now suppose you are implementing the <code>UIElement.<\/code><code>Find\u00adSub\u00adElements\u00adFor\u00adTouch\u00adTargeting<\/code>:<\/p>\n<pre>\/\/ C#\r\nvirtual override IEnumerable&lt;IEnumerable&lt;Point&gt;&gt; FindSubElementsForTouchTargeting();\r\n\r\n\/\/ C++\/CX\r\nvirtual IIterable&lt;IIterable&lt;Point&gt;^&gt;^ FindSubElementsForTouchTargeting() override;\r\n\r\n\/\/ C++\/WinRT\r\nIIterable&lt;IIterable&lt;Point&gt;&gt; FindSubElementsForTouchTargeting();\r\n<\/pre>\n<p>In C#, this is straightforward. You can have a list of lists:<\/p>\n<pre>virtual override IEnumerable&lt;IEnumerable&lt;Point&gt;&gt; FindSubElementsForTouchTargeting()\r\n{\r\n  var polygon1 = new List&lt;Point&gt; {\r\n        UpperLeftCorner1, UpperRightCorner1, LowerRightCorner1, LowerLeftCorner1,\r\n    };\r\n  var polygon2 = new List&lt;Point&gt; {\r\n        UpperLeftCorner2, UpperRightCorner2, LowerRightCorner2, LowerLeftCorner2,\r\n    };\r\n  var results = new List&lt;List&lt;Point&gt;&gt; { polygon1, polygon2 };\r\n  return results;\r\n}\r\n<\/pre>\n<p>Thanks to covariance, a <code>List&lt;List&lt;Point&gt;&gt;<\/code> is compatible with <code>IEnumerable&lt;IEnumerable&lt;Point&gt;&gt;<\/code> because <code>List&lt;T&gt;<\/code> is compatible with <code>IEnumeraable&lt;T&gt;<\/code>, and <code>IEnumeraable&lt;T&gt;<\/code> is covariant in <code>T<\/code>.<\/p>\n<p>C++ is not as lucky. The analogous code in C++\/CX would be something like this:<\/p>\n<pre>virtual override IEnumerable&lt;IEnumerable&lt;Point&gt;&gt; FindSubElementsForTouchTargeting()\r\n{\r\n  auto polygon1 = ref new Vector&lt;Point&gt;({\r\n        UpperLeftCorner1, UpperRightCorner1, LowerRightCorner1, LowerLeftCorner1,\r\n    });\r\n  auto polygon2 = ref new Vector&lt;Point&gt;({\r\n        UpperLeftCorner2, UpperRightCorner2, LowerRightCorner2, LowerLeftCorner2,\r\n    });\r\n  auto results = ref new Vector&lt;Vector&lt;Point&gt;&gt;({ polygon1, polygon2 });\r\n  return results;\r\n}\r\n<\/pre>\n<p>And in C++\/WinRT:<\/p>\n<pre>IIterable&lt;IIterable&lt;Point&gt;&gt; FindSubElementsForTouchTargeting()\r\n{\r\n  auto polygon1 = single_threaded_vector&lt;Point&gt;({\r\n        UpperLeftCorner1, UpperRightCorner1, LowerRightCorner1, LowerLeftCorner1,\r\n    });\r\n  auto polygon2 = single_threaded_vector&lt;Point&gt;({\r\n        UpperLeftCorner2, UpperRightCorner2, LowerRightCorner2, LowerLeftCorner2,\r\n    });\r\n  auto results = single_threaded_vector&lt;IVector&lt;Point&gt;&gt;({ polygon1, polygon2 });\r\n  return results;\r\n}\r\n<\/pre>\n<p>This code doesn&#8217;t work because there is no conversion from <code>Vector&lt;Vector&lt;Point&gt;^&gt;^<\/code> to <code>IIterable&lt;IIterable&lt;Point&gt;^&gt;^<\/code> (C++\/CX) or from <code>IVector&lt;IVector&lt;Point&gt;&gt;<\/code> to <code>IIterable&lt;IIterable&lt;Point&gt;&gt;<\/code> (C++\/WinRT). The automatic conversion gets you part way there, but it can&#8217;t convert the inner portion due to the lack of covariance.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<th style=\"padding: 3px; border: solid 1px black;\" colspan=\"3\">C++\/CX<\/th>\n<th style=\"padding: 3px; border: solid 1px black;\" colspan=\"3\">C++\/WinRT<\/th>\n<\/tr>\n<tr>\n<td style=\"padding: 3px 0 0 3px; border-left: solid 1px black; text-align: right;\"><tt><span style=\"color: blue;\">Vector<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 0 0 0; text-align: right;\"><tt>Vector&lt;<\/tt><\/td>\n<td style=\"padding: 3px 3px 0 0; text-align: right;\"><tt>Point&gt;^&gt;^<\/tt><\/td>\n<td style=\"padding: 3px 0 0 3px; border-left: solid 1px black; text-align: right;\"><tt><span style=\"color: blue;\">IVector<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 0 0 0; text-align: right;\"><tt>IVector<\/tt><\/td>\n<td style=\"padding: 3px 3px 0 0; border-right: solid 1px black; text-align: right;\"><tt>&lt;Point&gt;&gt;<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 0 0 3px 3px; border-left: solid 1px black; text-align: center;\">\u2193<\/td>\n<td style=\"padding: 0 0 3px 0;\">\u00a0<\/td>\n<td style=\"padding: 0 3px 3px 0;\">\u00a0<\/td>\n<td style=\"padding: 0 0 3px 3px; border-left: solid 1px black; text-align: center;\">\u2193<\/td>\n<td style=\"padding: 0 0 3px 0;\">\u00a0<\/td>\n<td style=\"padding: 0 3px 3px 0; border-right: solid 1px black;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 3px 0 0 3px; border-left: solid 1px black; text-align: right;\"><tt><span style=\"color: blue;\">IIterable<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 0 0 0; text-align: right;\"><tt><span style=\"color: red;\">Vector<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 3px 0 0; text-align: right;\"><tt>Point&gt;^&gt;^<\/tt><\/td>\n<td style=\"padding: 3px 0 0 3px; border-left: solid 1px black; text-align: right;\"><tt><span style=\"color: blue;\">IIterable<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 0 0 0; text-align: right;\"><tt><span style=\"color: red;\">IVector<\/span><\/tt><\/td>\n<td style=\"padding: 3px 3px 0 0; border-right: solid 1px black; text-align: right;\"><tt>&lt;Point&gt;&gt;<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 0 0 3px 3px; border-left: solid 1px black;\">\u00a0<\/td>\n<td style=\"padding: 0 0 3px 0; text-align: center; position: relative;\">\n<div style=\"position: absolute; top: 0; width: 100%;\">\u274c<\/div>\n<div>\u2193<\/div>\n<\/td>\n<td style=\"padding: 0 3px 3px 0;\">\u00a0<\/td>\n<td style=\"padding: 0 0 3px 3px; border-left: solid 1px black;\">\u00a0<\/td>\n<td style=\"padding: 0 0 3px 0; text-align: center; position: relative;\">\n<div style=\"position: absolute; top: 0; width: 100%;\">\u274c<\/div>\n<div>\u2193<\/div>\n<\/td>\n<td style=\"padding: 0 3px 3px 0; border-right: solid 1px black;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 3px 0 0 3px; border-left: solid 1px black; border-bottom: solid 1px black; text-align: right;\"><tt><span style=\"color: blue;\">IIterable<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 0 0 0; border-bottom: solid 1px black; text-align: right;\"><tt><span style=\"color: red;\">IIterable<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 3px 0 0; border-bottom: solid 1px black; text-align: right;\"><tt>Point&gt;^&gt;^<\/tt><\/td>\n<td style=\"padding: 3px 0 0 3px; border-left: solid 1px black; border-bottom: solid 1px black; text-align: right;\"><tt><span style=\"color: blue;\">IIterable<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 0 0 0; border-bottom: solid 1px black; text-align: right;\"><tt><span style=\"color: red;\">IIterable<\/span>&lt;<\/tt><\/td>\n<td style=\"padding: 3px 3px 0 0; border-right: solid 1px black; border-bottom: solid 1px black; text-align: right;\"><tt>&lt;Point&gt;&gt;<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>You have to declare the inner portion exactly correctly the first time. The language isn&#8217;t going to help you.<\/p>\n<pre>\/\/ C++\/CX\r\nvirtual override IEnumerable&lt;IEnumerable&lt;Point&gt;&gt; FindSubElementsForTouchTargeting()\r\n{\r\n  auto polygon1 = ref new Vector&lt;Point&gt;({\r\n        UpperLeftCorner1, UpperRightCorner1, LowerRightCorner1, LowerLeftCorner1,\r\n    });\r\n  auto polygon2 = ref new Vector&lt;Point&gt;({\r\n        UpperLeftCorner2, UpperRightCorner2, LowerRightCorner2, LowerLeftCorner2,\r\n    });\r\n  auto results = ref new Vector&lt;<span style=\"color: blue;\">IEnumerable<\/span>&lt;Point&gt;&gt;({ polygon1, polygon2 });\r\n  return results;\r\n}\r\n<\/pre>\n<p>And in C++\/WinRT:<\/p>\n<pre>IIterable&lt;IIterable&lt;Point&gt;&gt; FindSubElementsForTouchTargeting()\r\n{\r\n  auto polygon1 = single_threaded_vector&lt;Point&gt;({\r\n        UpperLeftCorner1, UpperRightCorner1, LowerRightCorner1, LowerLeftCorner1,\r\n    });\r\n  auto polygon2 = single_threaded_vector&lt;Point&gt;({\r\n        UpperLeftCorner2, UpperRightCorner2, LowerRightCorner2, LowerLeftCorner2,\r\n    });\r\n  auto results = single_threaded_vector&lt;<span style=\"color: blue;\">IIterable<\/span>&lt;Point&gt;&gt;({ polygon1, polygon2 });\r\n  return results;\r\n}\r\n<\/pre>\n<p>You do lose the ability to index the <code>results<\/code> and access the original vectors, since by the time you put them into the <code>results<\/code>, they have been turned into <code>IIterable<\/code>s.<\/p>\n<p>C++\/WinRT gives you a little help here. If the iterable of iterables is a parameter to a function, then you can let C++\/WinRT auto-generate the outer iterable, at which point the automatic conversions will kick in for the inner objects because the type is being explicitly specified by the parameter.<\/p>\n<pre>extern void SomeMethod(winrt::param::iterable&lt;\r\n    IIterable&lt;Point&gt;&gt; const&amp; elementOutlines);\r\n\r\nauto polygon1 = single_threaded_vector&lt;Point&gt;({\r\n      UpperLeftCorner1, UpperRightCorner1, LowerRightCorner1, LowerLeftCorner1,\r\n  });\r\nauto polygon2 = single_threaded_vector&lt;Point&gt;({\r\n      UpperLeftCorner2, UpperRightCorner2, LowerRightCorner2, LowerLeftCorner2,\r\n  });\r\nSomeMethod({ polygon1, polygon2 });\r\n<\/pre>\n<p>That wasn&#8217;t too messy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You have to say exactly what you want, which may not be exactly what you have.<\/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-104346","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You have to say exactly what you want, which may not be exactly what you have.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104346","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=104346"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104346\/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=104346"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104346"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104346"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}