{"id":105516,"date":"2021-08-04T07:00:00","date_gmt":"2021-08-04T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105516"},"modified":"2021-08-04T06:33:28","modified_gmt":"2021-08-04T13:33:28","slug":"20210804-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210804-00\/?p=105516","title":{"rendered":"What is a static Windows Runtime class, how should I express it, and when should I use it?"},"content":{"rendered":"<p>The Windows Runtime has this thing called &#8220;static classes&#8221;. What are they?<\/p>\n<p>A static Windows Runtime class is a class that has no instances. An example of this is the <code>FileIO<\/code> class:<\/p>\n<pre>static runtimeclass FileIO\r\n{\r\n    static IAsyncOperation&lt;String&gt; ReadTextAsync(IStorageFile file);\r\n    static IAsyncAction WriteText(IStorageFile file, String contents);\r\n\r\n    static IAsyncOperation&lt;IVector&lt;String&gt;&gt; ReadLinesAsync(IStorageFile file);\r\n    static IAsyncAction WriteLines(IStorageFile file, IIterable&lt;String&gt; lines);\r\n\r\n    static IAsyncOperation&lt;IBuffer&gt; ReadBufferAsync(IStorageFile file);\r\n    static IAsyncAction WriteBuffer(IStorageFile file, IBuffer buffer);\r\n\r\n    \/* etc *\/\r\n}\r\n<\/pre>\n<p>There is no <code>FileIO<\/code> object. You can&#8217;t say<\/p>\n<pre>\/\/ C#\r\nvar fileIO = new FileIO(); \/\/ nope\r\n\r\n\/\/ C++\/WinRT\r\nFileIO fileIO; \/\/ nope\r\nauto fileIO = FileIO(); \/\/ nope\r\n\r\n\/\/ C++\/CX\r\nauto fileIO = ref new FileIO(); \/\/ nope\r\n\r\n\/\/ JavaScript\r\nlet fileIO = new FileIO(); \/\/ nope\r\n<\/pre>\n<p>None of these work because <code>FileIO<\/code> is not an object. It&#8217;s just a way to gather related functions under a common umbrella, similar to a namespace.<\/p>\n<p>The term <code>static class<\/code> comes from the C# concept of the same name.<\/p>\n<p>The way to express a static class is to put the word <code>static<\/code> in front of the class declaration, like we did above with <code>FileIO<\/code>:<\/p>\n<pre><span style=\"color: blue;\">static<\/span> runtimeclass FileIO\r\n{\r\n    ...\r\n}\r\n<\/pre>\n<p>If you leave out the <code>static<\/code> keyword (which is easily overlooked), then what you have is a class with no nonstatic members, also known as an <i>empty class<\/i>.<\/p>\n<p>Empty classes are also a thing. They represent objects that you can&#8217;t do anything with except pass to other methods. They are often used to capture some information into an opaque object which can then be passed around.<\/p>\n<pre>[default_interface]\r\nruntimeclass WidgetLocation\r\n{\r\n}\r\n\r\nruntimeclass Widget\r\n{\r\n    WidgetLocation Location;\r\n}\r\n\r\n\/\/ C#\r\n\/\/ Move widget1 to the same location as widget2.\r\nwidget1.Location = widget2.Location;\r\n<\/pre>\n<p>The only thing you can do with a <code>Widget\u00adLocation<\/code> is pass it to something that wants a <code>Widget\u00adLocation<\/code>. You can&#8217;t inspect the <code>Widget\u00adLocation<\/code> to learn anything about it directly. You have to ask somebody else to interpret it for you.<\/p>\n<p>The <code>FileIO<\/code> class is not one of these empty classes. It&#8217;s not like you get an opaque <code>FileIO<\/code> object that represents some internal state. There simply isn&#8217;t any such thing as a <code>FileIO<\/code> object at all.<\/p>\n<p>And for that case, what you have is a static class.<\/p>\n<p><b>Bonus chatter<\/b>: The MIDL3 compiler leads you into a pit of failure here. There are five patterns for runtime classes:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>\u00a0<\/th>\n<th>No static members<\/th>\n<th>Has static members<\/th>\n<\/tr>\n<tr>\n<th>No instances<\/th>\n<td valign=\"top\">N\/A<\/td>\n<td valign=\"top\"><code>static runtimeclass C<br \/>\n        {<br \/>\n        \u00a0static void S();<br \/>\n        }<\/code><\/td>\n<\/tr>\n<tr>\n<th>Has instances, empty<\/th>\n<td valign=\"top\"><code>[default_interface]<br \/>\n        runtimeclass C<br \/>\n        {<\/p>\n<p>        }<\/code><\/td>\n<td valign=\"top\"><code>[default_interface]<br \/>\n        runtimeclass C<br \/>\n        {<br \/>\n        \u00a0static void S();<br \/>\n        }<\/code><\/td>\n<\/tr>\n<tr>\n<th>Has instances, nonempty<\/th>\n<td valign=\"top\"><code>runtimeclass C<br \/>\n        {<br \/>\n        \u00a0void M();<\/p>\n<p>        }<\/code><\/td>\n<td valign=\"top\"><code>runtimeclass C<br \/>\n        {<br \/>\n        \u00a0void M();<br \/>\n        \u00a0static void S();<br \/>\n        }<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The top left corner is N\/A because if a class has no static members and no instances, then there&#8217;s nothing there.<\/p>\n<p>If there are no instances, then you say that you are a <code>static runtimeclass<\/code>. That takes care of the first row.<\/p>\n<p>If you are an empty class, then you need to say <code>[default_interface]<\/code> to tell the MIDL3 compiler that you want it to generate an empty interface to represent the empty instances.<\/p>\n<p>If you are a nonempty class, then you don&#8217;t need to say <code>[default_interface]<\/code> (although it&#8217;s harmless to do so) because the MIDL3 compiler is already forced to generate an interface to represent the instance methods.<\/p>\n<p>Notice that this case<\/p>\n<pre>runtimeclass C\r\n{\r\n static void S();\r\n}\r\n<\/pre>\n<p>is not even on the list of legal declarations!<\/p>\n<p>The MIDL3 compiler lets you use this erroneous declaration. It assumes that you meant &#8220;Has instances, empty&#8221; and secretly synthesizes an empty <code>[default_interface]<\/code> for you. It&#8217;s only when you try to do anything that requires this synthesized <code>[default_interface]<\/code>, that the MIDL3 compiler then yells at you, &#8220;Hey, you forgot to say <code>[default_interface]<\/code>.&#8221;<\/p>\n<p>The trap is that if you intended the class to be a static class, but simply forgot to apply the <code>static<\/code> keyword, then you will never do anything that requires the synthesized <code>[default_interface]<\/code>, and you never get any error message. The secretly synthesized empty interface is still generated, but it is completely useless since there is no way to obtain any objects that implement it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The underlying question is &#8220;Can you even make one?&#8221;<\/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-105516","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The underlying question is &#8220;Can you even make one?&#8221;<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105516","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=105516"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105516\/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=105516"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105516"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105516"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}