{"id":1145,"date":"2018-03-07T14:48:20","date_gmt":"2018-03-07T06:48:20","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/seteplia\/?p=1145"},"modified":"2019-06-11T22:05:36","modified_gmt":"2019-06-12T05:05:36","slug":"the-in-modifier-and-the-readonly-structs-in-c","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/the-in-modifier-and-the-readonly-structs-in-c\/","title":{"rendered":"The \u2018in\u2019-modifier and the readonly structs in C#"},"content":{"rendered":"<p>C# 7.2 got two very important features for high-performance scenarios &#8212; the readonly structs and the <code>in<\/code> parameters. But to understand why this additions are so important and how they&#8217;re related to each other we should look back in history.<\/p>\n<p>As you probably know, the .NET ecosystem has two family of types &#8212; the value types (a.k.a. structs) and the reference types (a.k.a. classes) (*). There are a plenty of differences between them but the main one is <strong>the semantics<\/strong>. The value types follow the value semantics: (1) two instances of a value type are equal if all the data members are equal and (2) the value type instance by default is passed around by value, i.e. by creating a copy of the original instance. The reference types, on the other hand, follow the &#8220;reference semantics&#8221;: (1) two instances of a reference type are equal if they point to the same instance in the managed heap (**) and (2) a reference type instance is passed by reference, i.e. by passing the pointer to the original instance in the managed heap.<\/p>\n<p>(*) The third category is managed references but for the sake of this discussion we can ignore them. (**) This behavior can be overriden by overriding <code>Equals<\/code> and <code>GetHashCode<\/code>.<\/p>\n<h4>Readonly fields of the value types<\/h4>\n<p>To enforce the value semantics of value types the C# compiler performs some actions that could be not obvious from the developer&#8217;s point of view. Here is an example:<\/p>\n<pre class=\"lang:default decode:true \">internal class ReadOnlyEnumerator\r\n{\r\n    private readonly List&lt;int&gt;.Enumerator _enumerator;\r\n\r\n    public ReadOnlyEnumerator(List&lt;int&gt; list)\r\n    {\r\n        Contract.Requires(list.Count &gt;= 1);\r\n        _enumerator = list.GetEnumerator();\r\n    }\r\n\r\n    public void PrintTheFirstElement()\r\n    {\r\n        _enumerator.MoveNext();\r\n        Console.WriteLine(_enumerator.Current);\r\n    }\r\n\r\n}\r\n\r\n\r\nvar roe = new ReadOnlyEnumerator(new List&lt;int&gt;{1,2});\r\nroe.PrintTheFirstElement();<\/pre>\n<p>The output is not obvious: &#8220;0&#8221;.<\/p>\n<p>The <code>readonly<\/code> modifier has slightly different observable effects for the value types and for the reference types. A readonly field of a reference type is like a constant pointer: the compiler will make sure that the field is not reassigned outside the constructor even though the referenced object&#8217;s state may change (if the referenced type is mutable). A readonly field of value type means that the value itself should be the same for the entire lifetime of the enclosing instance. To prevent any potential mutations, the compiler makes a defensive copy of the field each time a method or a property is used.<\/p>\n<p>Under the hood <code>PrintTheFirstElement<\/code> does the following:<\/p>\n<pre class=\"lang:default decode:true \">public void PrintTheFirstElement_Decompiled()\r\n{\r\n    \/\/ Defensive copy\r\n    var localEnumerator = _enumerator;\r\n    localEnumerator.MoveNext();\r\n\r\n    \/\/ Defensive copy (2)\r\n    localEnumerator = _enumerator;\r\n    Console.WriteLine(localEnumerator.Current);\r\n}<\/pre>\n<p>This is a real issue and the reason why <strong>mutable value types are evil<\/strong>. A couple of months back I spent a few hours debugging a similar issue caused by a readonly <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.spinlock%28v=vs.110%29.aspx?f=255&amp;MSPPError=-2147217396\"><code>SpinLock<\/code><\/a> field.<\/p>\n<h4>The performance implications of the defensive copies<\/h4>\n<p>Mutability is not the only problem. The defensive copies can affect performance even when the structs are immutable.<\/p>\n<pre class=\"lang:default decode:true \">public struct FairlyLargeStruct\r\n{\r\n    private readonly long l1, l2, l3, l4;\r\n    public int N { get; }\r\n    public FairlyLargeStruct(int n) : this() =&gt; N = n;\r\n}<\/pre>\n<p>Let&#8217;s see what the difference between <code>readonly<\/code> and non-<code>readonly<\/code> access of the field:<\/p>\n<pre class=\"lang:default decode:true \">private FairlyLargeStruct _nonReadOnlyStruct = new FairlyLargeStruct(42);\r\nprivate readonly FairlyLargeStruct _readOnlyStruct = new FairlyLargeStruct(42);\r\nprivate readonly int[] _data = Enumerable.Range(1, 100_000).ToArray();\r\n        \r\n[Benchmark]\r\npublic int AggregateForNonReadOnlyField()\r\n{\r\n    int result = 0;\r\n    foreach (int n in _data)\r\n        result += n + _nonReadOnlyStruct.N;\r\n    return result;\r\n}\r\n\r\n[Benchmark]\r\npublic int AggregateForReadOnlyField()\r\n{\r\n    int result = 0;\r\n    foreach (int n in _data)\r\n        result += n + _readOnlyStruct.N;\r\n    return result;\r\n}<\/pre>\n<p>The results are:<\/p>\n<pre class=\"lang:default decode:true \">                       Method |      Mean |    Error |    StdDev | \r\n----------------------------- |----------:|---------:|----------:| \r\n AggregateForNonReadOnlyField |  87.92 us | 1.800 us |  3.677 us | \r\n    AggregateForReadOnlyField | 148.29 us | 4.226 us | 12.460 us |<\/pre>\n<p>The significant difference in the results caused by a defensive copy that is happening each time the readonly field is used. You may have heard that the size of the struct should be relatively small to avoid the overhead of passing it around to other methods. But as you can see, you may get a performance hit even when a fairly large struct is stored in a readonly field and never passed to another method.<\/p>\n<p>There are at least 3 solutions to this problem:<\/p>\n<p><strong>1. Use fields instead of properties<\/strong><\/p>\n<pre class=\"lang:default decode:true \">public struct FairlyLargeStruct\r\n{\r\n    private readonly long l1, l2, l3, l4;\r\n    public readonly int N;\r\n    public FairlyLargeStruct(int n) : this() =&gt; N = n;\r\n}<\/pre>\n<p>If the C# compiler sees an access to a <code>FairlyLargeStruct<\/code>&#8216;s field <code>N<\/code> via <code>readonly<\/code>variable, it won&#8217;t create a defensive copy, because it knows that reading a field <code>N<\/code> is side effect free. This solution is not sustainable for a real world because <code>FairlyLargeStruct<\/code> could have methods as well, and even if there are no methods or properties today, it&#8217;s just a matter of time when someone from your team will refactor the code to switch from fields to properties causing a performance regression.<\/p>\n<p><strong>2. Use non-readonly field of <code>FairlyLargeStruct<\/code><\/strong><\/p>\n<pre class=\"lang:default decode:true \">\/\/ Use non-readonly field to avoid redundant defensive copy on each field access\r\nprivate \/*readonly*\/FairlyLargeStruct _fairlyLargeStruct;<\/pre>\n<p><strong>3. Use readonly structs<\/strong><\/p>\n<pre class=\"lang:default decode:true \">public readonly struct FairlyLargeStruct\r\n{\r\n    private readonly long l1, l2, l3, l4;\r\n    public int N { get; }\r\n    public FairlyLargeStruct(int n) : this() =&gt; N = n;\r\n}<\/pre>\n<h4>The readonly structs<\/h4>\n<p>C# 7.2 allows a user to enforce immutability for a given struct by using the <code>readonly<\/code>modifier. As you may see in a moment it is good for performance but it is also very useful from a design perspective: readonly structs clearly carries the intention that the instance is immutable and can&#8217;t be changed (without some tricks like reflection).<\/p>\n<p>The <code>reaodnly<\/code> modifier enforces the following behavior:<\/p>\n<ol>\n<li>The compiler checks that the struct is indeed immutable and consists only of readonly fields and\/or readonly properties (properties like <code>public int Foo {get; private set;}<\/code> are not readonly).<\/li>\n<li>Allows the compiler to skip defensive copies in some contexts, like when a readonly field of such a struct is used.<\/li>\n<\/ol>\n<p>Here are the benchmark results for <code>readonly struct FairlyLargeStruct<\/code>:<\/p>\n<pre class=\"lang:default decode:true \">                       Method |     Mean |    Error |   StdDev | \r\n----------------------------- |---------:|---------:|---------:| \r\n AggregateForNonReadOnlyField | 91.19 us | 1.811 us | 2.597 us | \r\n    AggregateForReadOnlyField | 89.25 us | 1.775 us | 3.705 us |<\/pre>\n<h4>The <code>in<\/code>-modifier<\/h4>\n<p>The very first version of the C# language had 3 ways of passing the arguments: by value (no modifier), by reference (with <code>ref<\/code> modifier) and as an output parameter (with <code>out<\/code> modifier) (***)<\/p>\n<p>(***) Under the hood the CLR has only two options: passing by value and passing by reference. The <code>out<\/code> modifier is the same as <code>ref<\/code> modifier plus the compiler checks for definite assignment.<\/p>\n<p>C# 7.2 introduces the third way of passing arguments: using <code>in<\/code>-modifier.<\/p>\n<p>The <code>in<\/code>-modifier is a way to pass the argument via readonly reference. Under the hood, the argument is passed by reference with a special attribute (<code>System.Runtime.CompilerServices.IsReadOnlyAttribute<\/code>), and the compiler makes sure that the method does not modify the parameter.<\/p>\n<pre class=\"lang:default decode:true \">public void Foo(in string s)\r\n{\r\n    \/\/ Cannot assign to variable 'in string' because it is a readonly variable\r\n    s = string.Empty;\r\n}<\/pre>\n<p>This simple language change has a large set of consequences.<\/p>\n<ol>\n<li>You can&#8217;t create an overload that differs only by <code>in<\/code>, <code>ref<\/code>, <code>out<\/code>. This is expected, because the <code>in<\/code> modifier is the same the <code>ref<\/code>-modifier under the hood with some additional logic from the compiler.<\/li>\n<li>You can&#8217;t use the <code>in<\/code>-modifier for async methods and iterator blocks.<\/li>\n<\/ol>\n<pre class=\"lang:default decode:true \">\/\/ Async methods cannot have ref or out parameters\r\nasync Task ByInAsync(in string s) =&gt; await Task.Yield();<\/pre>\n<p>This is expected as well because you can&#8217;t use <code>ref<\/code>\/<code>out<\/code> modifiers in these contexts as well. The restriction is just a side-effect of how <a href=\"\/Program Files\/Microsoft VS Code\/resources\/app\/out\/vs\/workbench\/parts\/html\/browser\/\">async methods are implemented<\/a><a href=\"https:\/\/blogs.msdn.microsoft.com\/seteplia\/2017\/11\/30\/dissecting-the-async-methods-in-c\/\">https:\/\/blogs.msdn.microsoft.com\/seteplia\/2017\/11\/30\/dissecting-the-async-methods-in-c\/<\/a>.<\/p>\n<ol start=\"3\">\n<li>You <strong>can<\/strong> pass a variable from a using block as an <code>in<\/code>-argument, even though it is impossible for <code>ref<\/code>\/<code>out<\/code> parameters:<\/li>\n<\/ol>\n<pre class=\"lang:default decode:true \">struct Disposable : IDisposable\r\n{\r\n    public void Dispose() { }\r\n}\r\n\r\npublic void DisposableSample()\r\n{\r\nusing (var d = new Disposable())\r\n{\r\n    \/\/ Ok\r\n    ByIn(d);\r\n    \/\/ Cannot use 'd' as a ref or out value because it is a 'using variable'\r\n    \/\/ByRef(ref d);\r\n}\r\n\r\nvoid ByRef(ref Disposable disposable) { }\r\nvoid ByIn(in Disposable disposable) { }<\/pre>\n<p>This is already interesting. Apparently, the restriction that &#8216;using variable&#8217; cannot be passed by reference is the compiler restriction, not the CLR one. And in this case, the restriction is removed because it is indeed safe to pass the variable as <code>in<\/code> argument.<\/p>\n<ol start=\"4\">\n<li>Default values for <code>in<\/code>-parameters Here is another difference between <code>in<\/code>-parameters and <code>ref<\/code>\/<code>out<\/code>: the <code>in<\/code>-parameter could have a default value:<\/li>\n<\/ol>\n<pre class=\"lang:default decode:true \">public int ByIn(in string s = \"\") =&gt; s.Length;<\/pre>\n<ol start=\"5\">\n<li>You <strong>can<\/strong> make an overload that differs only by <code>in<\/code> modifier:<\/li>\n<\/ol>\n<pre class=\"lang:default decode:true \">public int Foo(in string s) =&gt; s.Length;\r\npublic int Foo(string s) =&gt; s.Length;<\/pre>\n<p>This case is tricky because the behavior is language-version-specific. For instance, in C# 7.2 (the first version that added this feature), it was impossible to call the second overload:<\/p>\n<pre class=\"lang:default decode:true \">string s = string.Empty;\r\nFoo(in s);\r\n\/\/ The call is ambiguous between the following methods or properties: \r\n\/\/ 'WeirdOverload.Foo(in string)' and 'WeirdOverload.Foo(string)'\r\nFoo(s);<\/pre>\n<p>But this behavior was <a href=\"https:\/\/github.com\/dotnet\/csharplang\/issues\/945\">fixed<\/a> in C# 7.3 and now, <code>Foo(s)<\/code> is resolved to <code>Foo(string s)<\/code>.<\/p>\n<p>But why the <code>in<\/code>-modifier is optional on the call-site? As we&#8217;ll see in a moment, <code>in<\/code>-modifier can be very useful for high-performance scenarios, and this behavior simplifies the adoption of this feature:<\/p>\n<pre class=\"lang:default decode:true \">public int ByIn(in string s) =&gt; s.Length;\r\n\r\n\r\nstring s = string.Empty;\r\nByIn(in s); \/\/ Works fine\r\nByIn(s); \/\/ Works fine as well!\r\n\/\/ Fail?!?! An expression cannot be used in this context because it may not be passed or returned by reference\r\nByIn(in \"some string\");\r\nByIn(\"some string\"); \/\/ Works fine!<\/pre>\n<p>The behavior looks a bit inconsistent (all the other <code>ref<\/code>-like parameters should be passed using <code>in<\/code> or <code>out<\/code> keyword), the ability to omit the <code>in<\/code>-modifier makes a perfect sense to me (*****). Let suppose you&#8217;ve changed a library code to pass some fairly large struct using the <code>in<\/code>-modifier. You don&#8217;t want every client of your library to change the call site of this method in order to benefit from your change.<\/p>\n<p>(*****) What does not make sense to me at all is the error when the <code>in<\/code>-modifier is used with the literal.<\/p>\n<p>As you can see the <code>in<\/code>-modifier is a bit trickier than you might think. Semantically it is just another form of &#8220;input&#8221; parameters, very similar to passing an argument by value. On the other hand the <code>in<\/code>-modifier is implemented as a <code>ref<\/code>-parameter making some scenarios like async methods, impossible.<\/p>\n<p>But even with the existing restrictions, the new modifier is fairly useful because it helps to express the intent more clearly, and, as we&#8217;ll see in a moment, it helps in terms of performance.<\/p>\n<h4>Performance characteristics of the <code>in<\/code>-modifier<\/h4>\n<p>The <code>in<\/code> parameters of value types are passed by reference, and that means that the cost of passing an argument is constant and doesn&#8217;t depend on the size of the struct. This is a good news. But I have a bad news as well.<\/p>\n<p>Let&#8217;s change the original benchmark a little bit:<\/p>\n<pre class=\"lang:default decode:true \">public struct FairlyLargeStruct\r\n{\r\n    private readonly long l1, l2, l3, l4;\r\n    public int N { get; }\r\n    public FairlyLargeStruct(int n) : this() =&gt; N = n;\r\n}\r\n\r\n\r\nprivate readonly int[] _data = Enumerable.Range(1, 100_000).ToArray();\r\n\r\n[Benchmark]\r\npublic int AggregatePassedByValue()\r\n{\r\n    return DoAggregate(new FairlyLargeStruct(42));\r\n\r\n    int DoAggregate(FairlyLargeStruct largeStruct)\r\n    {\r\n        int result = 0;\r\n        foreach (int n in _data)\r\n            result += n + largeStruct.N;\r\n        return result;\r\n    }\r\n}\r\n\r\n[Benchmark]\r\npublic int AggregatePassedByIn()\r\n{\r\n    return DoAggregate(new FairlyLargeStruct(42));\r\n\r\n    int DoAggregate(in FairlyLargeStruct largeStruct)\r\n    {\r\n        int result = 0;\r\n        foreach (int n in _data)\r\n            result += n + largeStruct.N;\r\n        return result;\r\n    }\r\n}<\/pre>\n<p>Note, that <code>FairlyLargeStruct<\/code> struct is a normal struct, not a readonly one. Here are the results:<\/p>\n<pre class=\"lang:default decode:true \">                 Method |      Mean |     Error |    StdDev | \r\n----------------------- |----------:|----------:|----------:| \r\n AggregatePassedByValue |  71.24 us | 0.3150 us | 0.2278 us | \r\n    AggregatePassedByIn | 124.02 us | 3.2885 us | 9.6963 us |<\/pre>\n<p>Remember I&#8217;ve mentioned that the <code>in<\/code> parameters are similar to the readonly fields? To make sure that the parameter&#8217;s value stays the same the compiler make a defensive copy of the parameter every time a method\/property is used. If the struct is readonly then the compiler removes the defensive copy the same way as it does for readonly fields.<\/p>\n<p>It means that <strong>you should never pass a non-readonly struct as <code>in<\/code> parameter<\/strong>. It almost always will make the performance worse. Yes, the argument passing is cheaper, but once the parameter is used, the defensive copy will nullify the benefits or will make the performance worse. It could make sense if the struct is a C-like struct with a bunch of public fields and everyone in the team is aware that changing fields to properties would have a drastic performance impact on the application. But in this case, I would suggest passing the struct by reference instead.<\/p>\n<h4>Conclusion<\/h4>\n<ul>\n<li>The readonly structs are very useful from the design and the performance points of view.<\/li>\n<li>If the size of a readonly struct is bigger than <code>IntPtr.Size<\/code> you should pass it as an <code>in<\/code>-parameter for performance reasons.<\/li>\n<li>You may consider using the <code>in<\/code>-parameters for reference types to express your intent more clearly.<\/li>\n<li>You should never use a non-readonly struct as the <code>in<\/code> parameters because it may negatively affect performance and could lead to an obscure behavior if the struct is mutable.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>C# 7.2 got two very important features for high-performance scenarios &#8212; the readonly structs and the in parameters. But to understand why this additions are so important and how they&#8217;re related to each other we should look back in history. As you probably know, the .NET ecosystem has two family of types &#8212; the value [&hellip;]<\/p>\n","protected":false},"author":4004,"featured_media":37840,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[6699],"tags":[6695],"class_list":["post-1145","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c","tag-seteplia"],"acf":[],"blog_post_summary":"<p>C# 7.2 got two very important features for high-performance scenarios &#8212; the readonly structs and the in parameters. But to understand why this additions are so important and how they&#8217;re related to each other we should look back in history. As you probably know, the .NET ecosystem has two family of types &#8212; the value [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1145","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/4004"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=1145"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1145\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=1145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=1145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=1145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}