{"id":103066,"date":"2019-11-06T07:00:00","date_gmt":"2019-11-06T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103066"},"modified":"2019-11-05T16:30:08","modified_gmt":"2019-11-06T00:30:08","slug":"20191106-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191106-00\/?p=103066","title":{"rendered":"How can I have a C++ function that returns different types depending on what the caller wants?"},"content":{"rendered":"<p>Here&#8217;s something crazy: You have a function that has two different callers. One of them expects the function to return a widget. The other expects the function to return a doodad.<\/p>\n<pre>class widget;\r\nclass doodad;\r\n\r\nclass experiment\r\n{\r\npublic:\r\n    doodad get_entity();\r\n    widget get_entity();\r\n};\r\n<\/pre>\n<p>This is not allowed in C++. The return type of a function cannot be overloaded.<\/p>\n<p>But <a href=\"https:\/\/kennykerr.ca\"> Kenny Kerr<\/a> taught me how to fake it. What you do is return an object that doesn&#8217;t yet know whether it&#8217;s a widget or doodad.<\/p>\n<pre>class experiment\r\n{\r\npublic:\r\n    auto get_entity()\r\n    {\r\n        struct result\r\n        {\r\n            operator widget()\r\n            {\r\n                return experiment-&gt;get_entity_as_widget();\r\n            }\r\n\r\n            operator doodad()\r\n            {\r\n                return experiment-&gt;get_entity_as_doodad();\r\n            }\r\n\r\n            experiment* experiment;\r\n        };\r\n        return result{ this };\r\n    }\r\n};\r\n<\/pre>\n<p>The thing that is returned is neither a widget nor a doodad, but observing it will trigger a collapse to one or the other.<\/p>\n<pre>widget w = exp.get_entity();\r\ndoodad p = exp.get_entity();\r\n<\/pre>\n<p>In the first call, the <code>get_<\/code><code>entity()<\/code> returns the private <code>result<\/code> type, and then immediately assigns it to a variable of type <code>widget<\/code>. This triggers the <code>operator widget()<\/code> conversion operator, which calls <code>get_<\/code><code>entity_<\/code><code>as_<\/code><code>widget<\/code>.<\/p>\n<p>Similarly, the second call obtains the private <code>result<\/code> type and converts it to a <code>doodad<\/code>, which winds up calling <code>get_<\/code><code>entity_<\/code><code>as_<\/code><code>doodad<\/code>.<\/p>\n<p>The wave function collapse could be triggered by anything that accepts a conversion.<\/p>\n<pre>move_widget(exp.get_entity()); \/\/ will call get_entity_as_widget\r\nsignal_doodad(exp.get_entity()); \/\/ will call get_entity_as_doodad\r\n<\/pre>\n<p>If you take the return value of <code>get_<\/code><code>entity<\/code> and save it in an <code>auto<\/code>, then the wave function hasn&#8217;t collapsed yet. It&#8217;s still not sure which thing it is.<\/p>\n<pre>auto entity = exp.get_entity();\r\n<\/pre>\n<p>The thing doesn&#8217;t become a widget or doodad until you convert it.<\/p>\n<pre>move_widget(entity); \/\/ calls get_entity_as_widget\r\n<\/pre>\n<p>Note that the call to <code>get_<\/code><code>entity_<\/code><code>as_<\/code><code>widget<\/code> is delayed until the conversion occurs.<\/p>\n<pre>auto entity = exp.get_entity();\r\nexp.replace_entity();\r\nmove_widget(entity); \/\/ calls get_entity_as_widget\r\n<\/pre>\n<p>Between calling <code>get_<\/code><code>entity<\/code> and converting the result to a widget, we changed the entity in the experiment. Not until the conversion occurs does the call to <code>get_<\/code><code>entity_<\/code><code>as_<\/code><code>widget<\/code> happen, at which point it will get the new entity rather than the original one. And of course, if you destroy the experiment, then the unresolved <code>entity<\/code> has a dangling pointer, and the behavior is undefined.<\/p>\n<p>This trick works best if the caller will convert the result <i>immediately<\/i> to its final type (widget or doodad).<\/p>\n<p>Of course, you could try to fix these problems, say by taking a strong reference to the <code>experiment<\/code> to prevent it from being destructed prematurely. Or you could call both <code>get_<\/code><code>entity_<\/code><code>as_<\/code><code>widget<\/code> and <code>get_<\/code><code>entity_<\/code><code>as_<\/code><code>doodad<\/code> as part of the constructor, and then hand out the appropriate type during the conversion. That would fix the &#8220;delayed evaluation&#8221; problem, but at a cost of doing eager evaluation of both branches, even if only one will end up being used.<\/p>\n<p>In the case where Kenny used it, it was to <a href=\"https:\/\/github.com\/microsoft\/xlang\/commit\/e8d4b6d0549cd68559fb222ec1dee569c3fa0b9d#diff-c8f92fdacb3edc5e2de5216ac2085b32R58\"> permit the <code>First<\/code> method to return a different iterator<\/a> depending on who&#8217;s asking for it. The underlying problem is the object wants to be able to produce a stream of <code>T<\/code> objects or <code>IInspectable<\/code> objects, so it implements both the <code>IIterable&lt;T&gt;::First()<\/code> and <code>IIterable&lt;IInspectable&gt;::First()<\/code> methods. The projection for those interfaces forward to the implementation&#8217;s <code>First()<\/code>, which forces <code>First()<\/code> to serve two masters. And the way he solved it was to return an ambiguous object, so that each master sees what it wants.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quantum superposition comes to C++.<\/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-103066","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Quantum superposition comes to C++.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103066","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=103066"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103066\/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=103066"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103066"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103066"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}