{"id":2203,"date":"2009-05-06T19:35:18","date_gmt":"2009-05-06T19:35:18","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2009\/05\/06\/mutable-value-types-the-good-the-bad-and-the-ugly\/"},"modified":"2009-05-06T19:35:18","modified_gmt":"2009-05-06T19:35:18","slug":"mutable-value-types-the-good-the-bad-and-the-ugly","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/mutable-value-types-the-good-the-bad-and-the-ugly\/","title":{"rendered":"Mutable value types: the good, the bad and the ugly"},"content":{"rendered":"<p>Fire up your favorite search engine, type in \u201cmutable value types\u201d and you might just feel a bit of pity for the poor little guys. It seems like <i>everyone<\/i> hates them. Truth be told, there\u2019s a lot to dislike about them but before we get into the nastiness of <i>mutable<\/i> value types, let\u2019s talk about why value types in general are oft-desirable.<\/p>\n<p>Value types are the Oscar De Lay Hoyas of the CLR\u2019s type system: they\u2019re extremely <i>fast<\/i> and <i>light<\/i>. While heap allocation in the CLR is already quite fast, it does incur some overhead compared to stack-allocated objects. Stack-allocated objects (and value types embedded in heap-allocated objects) don\u2019t need the garbage collector for reclamation and they don\u2019t need the object pointer and sync block index that every heap-allocated object has. A quick and dirty test shows that allocating stack-based objects in a loop can be an order of magnitude faster than heap-based objects. This speedup not only reflects that there\u2019s less work to allocate on the stack but that the CLR does some optimizations when using value types. Regardless of trickery, it\u2019s a valid scenario and the value remains: value types can be really really fast.<\/p>\n<p>This is why some, though few, types in Parallel Extensions are value types, even though they don\u2019t really carry value semantics. SpinLock and SpinWait are both mutable types that were born strictly in the service of performance \u2013 every millisecond we can shave off of their allocation time can result in overall application performance improvements. There are problems with value types (that I\u2019ll get to in a moment) and the Parallel Extension team spent quite a bit of time grappling with the tradeoffs between performance and usability. Ultimately, we decided that it\u2019s acceptable for advanced types that exist purely for performance to eschew some usability for speed.<\/p>\n<p>So what\u2019s the bad stuff? Well, value types come with value semantics, and that means that any time you pass one around you\u2019re transferring the<i> value<\/i> of the object, not the object itself. If a value type is assigned to another variable, whether that\u2019s via the assignment of a local variable or as a parameter to a method, the receptive variable is getting assigned a <i>copy<\/i> of the target object. <a href=\"https:\/\/blogs.msdn.com\/ericlippert\/archive\/2008\/05\/14\/mutating-readonly-structs.aspx\">Add a <i>readonly<\/i> modifier to a value-type field in C# and any time you even <i>access<\/i> that field, you\u2019re getting a copy<\/a>. For mutable value-types, the danger is clear: once a value-type has been copied, mutations will reflect only in the copy.<\/p>\n<p>This is really bad news for something like a SpinLock where a single instance must be shared between multiple threads to work properly. Consider the following C# example, where we use a collection of SpinLocks to protect partitions of data:<\/p>\n<pre class=\"csharpcode\">List&lt;SpinLock&gt; locks = InitializeLocks();\n...\n<span class=\"rem\">\/\/ on some number of threads<\/span>\nSpinLock partitionLock = locks[myIndex]; <span class=\"rem\">\/\/ BUG!<\/span>\n\n<span class=\"kwrd\">bool<\/span> lockIsTaken = <span class=\"kwrd\">false<\/span>;\n<span class=\"kwrd\">try<\/span>\n{\n    partitionLock.Enter(<span class=\"kwrd\">ref<\/span> lockIsTaken);\n    UpdatePartition(myIndex);\n}\n<span class=\"kwrd\">finally<\/span> { <span class=\"kwrd\">if<\/span> (lockIsTaken) partitionLock.Exit(); }<\/pre>\n<p>The seemingly innocuous storage of locks in a List gives us one gnarly concurrency bug. Because SpinLock is a value type, when we retrieve a partition lock via List\u2019s indexer, we actually get a new copy of a SpinLock and our critical section no longer executes with mutual exclusion. Extension methods, which take the this-parameter by value, suffer from the same danger.<\/p>\n<p>So take heed of this issue. In general, don\u2019t use the value types unless you\u2019re sure it\u2019s going to give you the performance increases you need. When you have to use them, avoid passing them around and do so by reference, if you must. Document the dangers in your source. Finally, never, ever, put a <i>readonly<\/i> modifier on a SpinLock or SpinWait field.<\/p>\n<p>Alternatively, if you want the functionality of SpinLock but need to pass it around and don\u2019t mind the extra perf hit during allocation, you could always write a SpinLock wrapper class that can safely be passed around. Here\u2019s a very simple version:<\/p>\n<pre class=\"csharpcode\"><span class=\"kwrd\">class<\/span> SafeSpinLock\n{\n      <span class=\"kwrd\">private<\/span> SpinLock m_lock = <span class=\"kwrd\">new<\/span> SpinLock();\n\n      <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">void<\/span> Enter( <span class=\"kwrd\">ref<\/span> <span class=\"kwrd\">bool<\/span> isTaken )\n      {\n          m_lock.Enter( <span class=\"kwrd\">ref<\/span> isTaken );\n      }\n\n      <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">void<\/span> Exit()\n      {\n          m_lock.Exit();\n      }\n}<\/pre>\n<p>.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, &#8220;Courier New&#8221;, courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }<\/p>\n<p>.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, &#8220;Courier New&#8221;, courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fire up your favorite search engine, type in \u201cmutable value types\u201d and you might just feel a bit of pity for the poor little guys. It seems like everyone hates them. Truth be told, there\u2019s a lot to dislike about them but before we get into the nastiness of mutable value types, let\u2019s talk about [&hellip;]<\/p>\n","protected":false},"author":486,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[],"class_list":["post-2203","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam"],"acf":[],"blog_post_summary":"<p>Fire up your favorite search engine, type in \u201cmutable value types\u201d and you might just feel a bit of pity for the poor little guys. It seems like everyone hates them. Truth be told, there\u2019s a lot to dislike about them but before we get into the nastiness of mutable value types, let\u2019s talk about [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2203","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/486"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=2203"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2203\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=2203"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=2203"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=2203"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}