{"id":106167,"date":"2022-01-17T07:00:00","date_gmt":"2022-01-17T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106167"},"modified":"2022-01-17T08:52:27","modified_gmt":"2022-01-17T16:52:27","slug":"20220117-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220117-00\/?p=106167","title":{"rendered":"C# and C++ type aliases and their consequences"},"content":{"rendered":"<p>The C# and C++ language provide ways to introduce shorter names for things. These shortcuts do not have their own identities; they merely let one name be used as a shorthand for the other thing.<\/p>\n<pre>\/\/ C#\r\nusing Console = System.Console;\r\n\r\n\/\/ C++\r\nusing Project = Contoso::Project;\r\n<\/pre>\n<p>The C# and C++ programming languages call these <i>aliases<\/i>. You are allowing an existing type to go by a different name. It does not create a new type, and the new name is interchangeable with the old one.<\/p>\n<pre>\/\/ C++\r\nextern void UpdateProject(Contoso::Project&amp; project);\r\n\r\nvoid example()\r\n{\r\n    Project project;\r\n    UpdateProject(project); \/\/ this works\r\n}\r\n<\/pre>\n<p>Similarly, when you import a namespace with a <code>using<\/code> directive, the names from the other namespace are visible in your namespace, but they still belong to that other namespace.\u00b9<\/p>\n<pre>\/\/ C++\r\nnamespace Other\r\n{\r\n    struct OtherStruct;\r\n}\r\n\r\nnamespace Mine\r\n{\r\n    using namespace Other;\r\n}\r\n\r\nvoid Welcome(Mine::OtherStruct s);\r\n<\/pre>\n<p>The signature of the <code>Welcome<\/code> function is <code>void Welcome(Other::OtherStruct)<\/code>, not <code>void Welcome(Mine::OtherStruct)<\/code>.<\/p>\n<p>This trick also gives you a way to switch easily between two options:<\/p>\n<pre>#ifdef USE_CONTOSO_WIDGET\r\nusing Widget = Contoso::Widget;\r\n#else\r\nusing Widget = LitWare::Widget;\r\n#endif\r\n\r\n\/\/ code that uses Widget without caring whose widget it is\r\n<\/pre>\n<p>The fact that these aliases do not introduce new types means that when you go looking in the debugger, you will see the symbols decorated with their <i>original<\/i> names. Which can be both a good thing and a bad thing.<\/p>\n<p>It&#8217;s a good thing if you want the original name to be the one seen by the outside world. For example, you might create aliases for commonly-used types in your component, but you want people outside your component to use the original names.<\/p>\n<pre>\/\/ component.h\r\n\r\nnamespace Component\r\n{\r\n    struct ReversibleWidget;\r\n\r\n    void CheckPolarity(ReversibleWidget const&amp;);\r\n}\r\n\r\n\/\/ component.cpp (implementation)\r\n#include&lt;component.h&gt;\r\n\r\nusing FlipWidget = Component::ReversibleWidget;\r\n\r\nvoid Component::CheckPolarity(FlipWidget const&amp; widget)\r\n{\r\n    ... do stuff ...\r\n}\r\n<\/pre>\n<p>Inside your component, you&#8217;d rather just call it a <code>FlipWidget<\/code>, because that was the internal code name when the product was being developed, and then later, management decided that its public name should be <code>ReversibleWidget<\/code>. You can create an alias that lets you continue using your internal code name, so you don&#8217;t have to perform a massive search-and-replace across the entire code base (and deal with all the merge conflicts that will inevitably arise).<\/p>\n<p>That the symbols are decorated with the original names can be a bad thing if the original name is an unwieldy mess, which is unfortunately the case with many classes in the C++ standard library.<\/p>\n<p>In the C++ standard library, <code>string<\/code> is an alias for <code>basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;<\/code>,\u00b2 so a function like<\/p>\n<pre>void FillLookupTable(std::map&lt;std::string, std::string&gt;&amp; table);\r\n<\/pre>\n<p>formally has the signature (deep breath)<\/p>\n<pre style=\"white-space: pre-wrap;\">FillLookupTable(std::map&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, std::less&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt;, std::allocator&lt;std::pair&lt;std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; const, std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt; &gt; &gt;&amp;):\r\n<\/pre>\n<p>Good luck typing that into a debugger.<\/p>\n<p>\u00b9 The fact that they remain in the original namespace has consequences for <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/adl\"> argument-dependent lookup<\/a>:<\/p>\n<pre>namespace X\r\n{\r\n    struct S {};\r\n    void fiddle(S const&amp;);\r\n}\r\n\r\nnamespace Y\r\n{\r\n    using namespace X;\r\n    void fiddle(S const&amp;);\r\n}\r\n\r\nvoid test()\r\n{\r\n    Y::S s;\r\n    fiddle(s); \/\/ X::fiddle, not Y::fiddle\r\n}\r\n<\/pre>\n<p>\u00b2 What you&#8217;re seeing is a combination of the type alias <i>and<\/i> the template default parameters.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just some idle thoughts, and what it means for debugging.<\/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-106167","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Just some idle thoughts, and what it means for debugging.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106167","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=106167"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106167\/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=106167"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106167"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106167"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}