{"id":13183,"date":"2010-08-10T07:00:01","date_gmt":"2010-08-10T07:00:01","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/08\/10\/everybody-thinks-about-clr-objects-the-wrong-way-well-not-everybody\/"},"modified":"2010-08-10T07:00:01","modified_gmt":"2010-08-10T07:00:01","slug":"everybody-thinks-about-clr-objects-the-wrong-way-well-not-everybody","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100810-01\/?p=13183","title":{"rendered":"Everybody thinks about CLR objects the wrong way (well not everybody)"},"content":{"rendered":"<p>\nMany people responded to\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/09\/10047586.aspx\">\nEverybody thinks about garbage collection the wrong way<\/a>\nby proposing variations on auto-disposal based on scope:\n<\/p>\n<ul>\n<li>&#8220;Any local variable that is IDisposable should\n    <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/09\/10047586.aspx#10048023\">\n    dispose itself when it goes out of scope<\/a>.&#8221;<\/p>\n<li>&#8220;You should be able to attach an attribute to a class that says\n    <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/09\/10047586.aspx#10047975\">\n    the destructor should be called immediately after leaving scope<\/a>.&#8221;<\/p>\n<li>&#8220;It should have\n    <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/08\/09\/10047586.aspx#10047964\">\n    promised to call finalizers on scope exit<\/a>.&#8221;\n<\/ul>\n<p>\nWhat these people fail to recognize is that they are dealing\nwith object <i>references<\/i>, not objects.\n(I&#8217;m restricting the discussion to reference types, naturally.)\nIn C++, you can put an object in a local variable.\nIn the CLR, you can only put an object <i>reference<\/i>\nin a local variable.\n<\/p>\n<p>\nFor those who think in terms of C++, imagine if it were impossible to\ndeclare instances of C++ classes as local variables on the stack.\nInstead, you had to declare a local variable that was a pointer\nto your C++ class, and put the object in the pointer.\n<\/p>\n<table BORDER=\"0\" CELLPADDING=\"5\">\n<tr>\n<th>C#<\/th>\n<th>C++<\/th>\n<\/tr>\n<tr>\n<td><\/td>\n<td VALIGN=\"baseline\">\n<pre>void Function(OtherClass o)\n{\n \/\/ No longer possible to declare objects\n \/\/ with automatic storage duration\n <strike>Color c(0,0,0);<\/strike>\n <strike>Brush b(c);<\/strike>\n <strike>o.SetBackground(b);<\/strike>\n}<\/td>\n<\/tr>\n<tr>\n    <td VALIGN=\"baseline\"><pre>void Function(OtherClass o)\n{\n Color c = new Color(0,0,0);\n Brush b = new Brush(c);\n o.SetBackground(b);\n}<\/pre>\n<\/td>\n<td VALIGN=\"baseline\">\n<pre>void Function(OtherClass* o)\n{\n Color* c = new Color(0,0,0);\n Brush* b = new Brush(c);\n o-&gt;SetBackground(b);\n}<\/td>\n<\/tr>\n<\/table>\n<p>\nThis world where you can only use pointers to refer to objects\nis the world of the CLR.\n<\/p>\n<p>\nIn the CLR,\nobjects never go out of scope because objects don't have scope.&sup1;\nObject <i>references<\/i> have scope.\nObjects are alive from the point of construction to the point\nthat the last <i>reference<\/i> goes out of scope or is otherwise destroyed.\n<\/p>\n<p>\nIf objects were auto-disposed when references went out of scope,\nyou'd have all sorts of problems.\nI will use C++ notation instead of CLR notation to emphasize\nthat we are working with references, not objects.\n(I can't use actual C++ references since you cannot change the referent\nof a C++ reference, something that is permitted by the CLR.)\n<\/p>\n<table BORDER=\"0\" CELLPADDING=\"5\">\n<tr>\n    <th>C#<\/th><th>C++<\/th>\n<\/tr>\n<tr>\n    <td VALIGN=\"baseline\"><pre>void Function(OtherClass o)\n{\n Color c = new Color(0,0,0);\n Brush b = new Brush(c);\n Brush b2 = b;\n o.SetBackground(b2);\n}<pre><\/td>\n    <td VALIGN=\"baseline\"><pre>void Function(OtherClass* o)\n{\n Color* c = new Color(0,0,0);\n Brush* b = new Brush(c);\n Brush* b2 = b;\n o-&gt;SetBackground(b2);\n <font COLOR=\"blue\">\/\/ automatic disposal when variables go out of scope\n dispose b2;\n dispose b;\n dispose c;\n dispose o;<\/font>\n}<\/pre>\n<\/td>\n<\/table>\n<p>\nOops, we just double-disposed the <code>Brush<\/code> object\nand probably prematurely disposed the <code>OtherClass<\/code> object.\nFortunately, disposal is idempotent, so the double-disposal is\nharmless (assuming you actually meant disposal and not destruction).\nThe introduction of <code>b2<\/code> was artificial in this example,\nbut you can imagine\n<code>b2<\/code> being, say, the leftover value in a variable\nat the end of a loop, in which case we just accidentally\ndisposed the last object in an array.\n<\/p>\n<p>\nLet's say there's some attribute you can put on a local variable or\nparameter to say that you don't want it auto-disposed on scope exit.\n<\/p>\n<table BORDER=\"0\" CELLPADDING=\"5\">\n<tr>\n<th>C#<\/th>\n<th>C++<\/th>\n<\/tr>\n<tr>\n<td VALIGN=\"baseline\">\n<pre>void Function([NoAutoDispose] OtherClass o)\n{\n Color c = new Color(0,0,0);\n Brush b = new Brush(c);\n [NoAutoDispose] Brush b2 = b;\n o.SetBackground(b2);\n}<pre><\/td>\n    <td VALIGN=\"baseline\"><pre>void Function([NoAutoDispose] OtherClass* o)\n{\n Color* c = new Color(0,0,0);\n Brush* b = new Brush(c);\n [NoAutoDispose] Brush* b2 = b;\n o-&gt;SetBackground(b2);\n <font COLOR=\"blue\">\/\/ automatic disposal when variables go out of scope\n dispose b;\n dispose c;<\/font>\n}<\/pre>\n<\/td>\n<\/table>\n<p>\nOkay, that looks good. We disposed the <code>Brush<\/code> object\nexactly once and didn't prematurely dispose the <code>OtherClass<\/code>\nobject that we received as a parameter.\n(Maybe we could make <code>[NoAutoDispose]<\/code> the default\nfor parameters to save people a lot of typing.)\nWe're good, right?\n<\/p>\n<p>\nLet's do some trivial code cleanup, like inlining the <code>Color<\/code>\nparameter.\n<\/p>\n<table BORDER=\"0\" CELLPADDING=\"5\">\n<tr>\n<th>C#<\/th>\n<th>C++<\/th>\n<\/tr>\n<tr>\n<td VALIGN=\"baseline\">\n<pre>void Function([NoAutoDispose] OtherClass o)\n{\n Brush b = new Brush(new Color(0,0,0));\n [NoAutoDispose] Brush b2 = b;\n o.SetBackground(b2);\n}<pre><\/td>\n    <td VALIGN=\"baseline\"><pre>void Function([NoAutoDispose] OtherClass* o)\n{\n Brush* b = new Brush(new Color(0,0,0));\n [NoAutoDispose] Brush* b2 = b;\n o-&gt;SetBackground(b2);\n <font COLOR=\"blue\">\/\/ automatic disposal when variables go out of scope\n dispose b;<\/font>\n}<\/pre>\n<\/td>\n<\/table>\n<p>\nWhoa, we just introduced a semantic change by what seemed like a harmless\ntransformation:\nThe <code>Color<\/code> object is no longer auto-disposed.\nThis is even more insidious than\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2006\/08\/04\/688527.aspx\">\nthe scope of a variable affecting its treatment by anonymous closures<\/a>,\nfor introduction of temporary variables to break up a complex expression\n(or removal of one-time temporary variables) are common transformations\nthat people expect to be harmless,\nespecially since many language transformations are expressed in terms\nof temporary variables.\nNow you have to remember to tag all of your temporary variables with\n<code>[NoAutoDospose]<\/code>.\n<\/p>\n<p>\nWait, we're not done yet.\nWhat does <code>SetBackground<\/code> do?\n<\/p>\n<table BORDER=\"0\" CELLPADDING=\"5\">\n<tr>\n<th>C#<\/th>\n<th>C++<\/th>\n<\/tr>\n<tr>\n<td VALIGN=\"baseline\">\n<pre>void OtherClass.SetBackground([NoAutoDispose] Brush b)\n{\n this.background = b;\n}<pre><\/td>\n    <td VALIGN=\"baseline\"><pre>void OtherClass::SetBackground([NoAutoDispose] Brush* b)\n{\n this-&gt;background = b;\n}<\/pre>\n<\/td>\n<\/table>\n<p>\nOops, there is still a reference to that <code>Brush<\/code> in the\n<code>o.background<\/code> member.\nWe disposed an object while there were still outstanding\nreferences to it.\nNow when the <code>OtherClass<\/code> object tries to use\nthe reference, it will find itself operating on a\ndisposed object.\n<\/p>\n<p>\nWorking backward, this means that we should have put a\n<code>[NoAutoDispose]<\/code> attribute on the <code>b<\/code>\nvariable.\nAt this point, it's six of one, a half dozen of the other.\nEither you put <code>using<\/code> around all the things\nthat you want auto-disposed or you put <code>[NoAutoDispose]<\/code>\non all the things that you don't.&sup2;\n<\/p>\n<p>\nThe C++ solution to this problem is to use something like\n<code>shared_ptr<\/code> and reference-counted objects,\nwith the assistance of <code>weak_ptr<\/code> to avoid reference cycles,\nand being very selective about which objects are allocated\nwith automatic storage duration.\nSure, you could try to bring this model of programming to the CLR,\nbut now you're just trying to\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/07\/12\/3821577.aspx\">\npick all the cheese off your cheeseburger<\/a>\nand intentionally going against the automatic memory management\ndesign principles of the CLR.\n<\/p>\n<p>\nI was sort of assuming that since you're here for CLR Week,\nyou're one of those people who actively chose to use the CLR\nand want to use it in the manner in which it was intended,\nrather than somebody who wants it to work like C++.\nIf you want C++, you know where to find it.\n<\/p>\n<p>\n<b>Footnote<\/b>\n<\/p>\n<p>\n&sup1; Or at least don't have scope in the sense we're discussing here.\n<\/p>\n<p>\n&sup2; As for an attribute for specific classes to have\nauto-dispose behavior,\nthat works only if all references to auto-dispose objects are\nin the context of a create\/dispose pattern.\nReferences to auto-dispose objects outside of the create\/dispose pattern\nwould need\nto be tagged with the <code>[NoAutoDispose]<\/code> attribute.\n<\/p>\n<pre>\n[AutoDispose] class Stream { ... };\nStream MyClass.GetSaveStream()\n{\n [NoAutoDispose] Stream stm;\n if (saveToFile) {\n  stm = ...;\n } else {\n  stm = ...;\n }\n return stm;\n}\nvoid MyClass Save()\n{\n \/\/ NB! do not combine into one line\n Stream stm = GetSaveStream();\n SaveToStream(stm);\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Many people responded to Everybody thinks about garbage collection the wrong way by proposing variations on auto-disposal based on scope: &#8220;Any local variable that is IDisposable should dispose itself when it goes out of scope.&#8221; &#8220;You should be able to attach an attribute to a class that says the destructor should be called immediately after [&hellip;]<\/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":[26],"class_list":["post-13183","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Many people responded to Everybody thinks about garbage collection the wrong way by proposing variations on auto-disposal based on scope: &#8220;Any local variable that is IDisposable should dispose itself when it goes out of scope.&#8221; &#8220;You should be able to attach an attribute to a class that says the destructor should be called immediately after [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13183","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=13183"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/13183\/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=13183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=13183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=13183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}