{"id":1025,"date":"2017-10-03T12:58:41","date_gmt":"2017-10-03T04:58:41","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/seteplia\/?p=1025"},"modified":"2019-06-11T22:35:10","modified_gmt":"2019-06-12T05:35:10","slug":"dissecting-the-local-functions-in-c-7","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/dissecting-the-local-functions-in-c-7\/","title":{"rendered":"Dissecting the local functions in C# 7"},"content":{"rendered":"<p>The Local functions is a new feature in C# 7 that allows defining a function inside another function.<\/p>\n<h4>When to use a local function?<\/h4>\n<p>The main idea of local functions is very similar to anonymous methods: in some cases creating a named function is too expensive in terms of cognitive load on a reader. Sometimes the functionality is inherently local to another function and it makes no sense to pollute the &#8220;outer&#8221; scope with a separate named entity.<\/p>\n<p>You may think that this feature is redundant because the same behavior can be achieved with anonymous delegates or lambda expressions. But this is not always the case. Anonymous functions have certain restrictions and their performance characteristics can be unsuitable for your scenarios.<\/p>\n<h4>Use Case 1: eager preconditions in iterator blocks<\/h4>\n<p>Here is a simple function that reads a file line by line. Do you know when the <code>ArgumentNullException<\/code> will be thrown?<\/p>\n<pre class=\"lang:default decode:true \">public static IEnumerable&lt;string&gt; ReadLineByLine(string fileName)\r\n{\r\n    if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName));\r\n    foreach (var line in File.ReadAllLines(fileName))\r\n    {\r\n        yield return line;\r\n    }\r\n}\r\n\r\n\/\/ When the error will happen?\r\nstring fileName = null;\r\n\/\/ Here?\r\nvar query = ReadLineByLine(fileName).Select(x =&gt; $\"\\t{x}\").Where(l =&gt; l.Length &gt; 10);\r\n\/\/ Or here?\r\nProcessQuery(query);<\/pre>\n<p>Methods with <code>yield return<\/code> in their body are special. They called <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/65zzykke%28v=vs.100%29.aspx?f=255&amp;MSPPError=-2147217396\">Iterator Blocks<\/a> and they&#8217;re lazy. This means that the execution of those methods is happening &#8220;by demand&#8221; and the first block of code in them will be executed only when the client of the method will call <code>MoveNext<\/code> on the resulting iterator. In our case, it means that the error will happen only in the <code>ProcessQuery<\/code> method because all the LINQ-operators are lazy as well.<\/p>\n<p>Obviously, the behavior is not desirable because the <code>ProcessQuery<\/code> method will not have enough information about the context of the <code>ArgumentNullException<\/code>. So it would be good to throw the exception eagerly &#8211; when a client calls <code>ReadLineByLine<\/code> but not when a client processes the result.<\/p>\n<p>To solve this issue we need to extract the validation logic into a separate method. This is a good candidate for anonymous function but anonymous delegates and lambda expressions do not support iterator blocks (*):<\/p>\n<p>(*) Lambda expressions in <a href=\"http:\/\/VB.NET\">VB.NET<\/a> can have an iterator block.<\/p>\n<pre class=\"lang:default decode:true \">public static IEnumerable&lt;string&gt; ReadLineByLine(string fileName)\r\n{\r\n    if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName));\r\n\r\n    return ReadLineByLineImpl();\r\n\r\n    IEnumerable&lt;string&gt; ReadLineByLineImpl()\r\n    {\r\n        foreach (var line in File.ReadAllLines(fileName))\r\n        {\r\n            yield return line;\r\n        }\r\n    }\r\n}<\/pre>\n<h4>Use Case 2: eager preconditions in async methods<\/h4>\n<p>Async methods have the similar issue with exception handling: any exception thrown in a method marked with <code>async<\/code> keyword (**) manifests itself in a faulted task:<\/p>\n<pre class=\"lang:default decode:true \">public static async Task&lt;string&gt; GetAllTextAsync(string fileName)\r\n{\r\n    if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName));\r\n    var result = await File.ReadAllTextAsync(fileName);\r\n    Log($\"Read {result.Length} lines from '{fileName}'\");\r\n    return result;\r\n}\r\n\r\n\r\nstring fileName = null;\r\n\/\/ No exceptions\r\nvar task = GetAllTextAsync(fileName);\r\n\/\/ The following line will throw\r\nvar lines = await task;<\/pre>\n<p>(**) Technically, <code>async<\/code> is a contextual keyword, but this doesn&#8217;t change my point.<\/p>\n<p>You may think that there is not much of a difference when the error is happening. But this is far from the truth. Faulted task means that the method itself failed to do what it was supposed to do. The failed task means that the problem is in the method itself or in one of the building blocks that the method relies on.<\/p>\n<p>Eager preconditions validation is especially important when the resulting task is passed around the system. In this case, it would be extremely hard to understand when and what went wrong. A local function can solve this issue:<\/p>\n<pre class=\"lang:default decode:true \">public static Task&lt;string&gt; GetAllTextAsync(string fileName)\r\n{\r\n    \/\/ Eager argument validation\r\n    if (string.IsNullOrEmpty(fileName)) throw new ArgumentNullException(nameof(fileName));\r\n    return GetAllTextAsync();\r\n\r\n    async Task&lt;string&gt; GetAllTextAsync()\r\n    {\r\n        var result = await File.ReadAllTextAsync(fileName);\r\n        Log($\"Read {result.Length} lines from '{fileName}'\");\r\n        return result;\r\n    }\r\n}<\/pre>\n<h4>Use Case 3: local function with iterator blocks<\/h4>\n<p>I found very annoying that you can&#8217;t use iterators inside a lambda expression. Here is a simple example: if you want to get all the fields in the type hierarchy (including the private once) you have to traverse the inheritance hierarchy manually. But the traversal logic is method-specific and should be kept as local as possible:<\/p>\n<pre class=\"lang:default decode:true \">public static FieldInfo[] GetAllDeclaredFields(Type type)\r\n{\r\n    var flags = BindingFlags.Instance | BindingFlags.Public |\r\n                BindingFlags.NonPublic | BindingFlags.DeclaredOnly;\r\n    return TraverseBaseTypeAndSelf(type)\r\n        .SelectMany(t =&gt; t.GetFields(flags))\r\n        .ToArray();\r\n\r\n    IEnumerable&lt;Type&gt; TraverseBaseTypeAndSelf(Type t)\r\n    {\r\n        while (t != null)\r\n        {\r\n            yield return t;\r\n            t = t.BaseType;\r\n        }\r\n    }\r\n}<\/pre>\n<h4>Use Case 4: recursive anonymous method<\/h4>\n<p>Anonymous functions can&#8217;t reference itself by default. To work around this restriction you should declare a local variable of a delegate type and then capture that local variable inside the lambda expression or anonymous delegate:<\/p>\n<pre class=\"lang:default decode:true \">public static List&lt;Type&gt; BaseTypesAndSelf(Type type)\r\n{\r\n    Action&lt;List&lt;Type&gt;, Type&gt; addBaseType = null;\r\n    addBaseType = (lst, t) =&gt;\r\n    {\r\n        lst.Add(t);\r\n        if (t.BaseType != null)\r\n        {\r\n            addBaseType(lst, t.BaseType);\r\n        }\r\n    };\r\n\r\n    var result = new List&lt;Type&gt;();\r\n    addBaseType(result, type);\r\n    return result;\r\n}<\/pre>\n<p>This approach is not very readable and similar solution with local function feels way more natural:<\/p>\n<pre class=\"lang:default decode:true \">public static List&lt;Type&gt; BaseTypesAndSelf(Type type)\r\n{\r\n    return AddBaseType(new List&lt;Type&gt;(), type);\r\n\r\n    List&lt;Type&gt; AddBaseType(List&lt;Type&gt; lst, Type t)\r\n    {\r\n        lst.Add(t);\r\n        if (t.BaseType != null)\r\n        {\r\n            AddBaseType(lst, t.BaseType);\r\n        }\r\n        return lst;\r\n    }\r\n}<\/pre>\n<h4>Use Case 5: when allocations matters<\/h4>\n<p>If you ever work on a performance critical application, then you know that anonymous methods are not cheap:<\/p>\n<ul>\n<li>Overhead of a delegate invocation (very very small, but it does exist).<\/li>\n<li><strong>2 heap allocations<\/strong> if a lambda captures local variable or argument of enclosing method (one for closure instance and another one for a delegate itself).<\/li>\n<li><strong>1 heap allocation<\/strong> if a lambda captures an enclosing instance state (just a delegate allocation).<\/li>\n<li><strong>0 heap allocations<\/strong> only if a lambda does not capture anything or captures a static state.<\/li>\n<\/ul>\n<p>But allocation pattern for local functions is different.<\/p>\n<pre class=\"lang:default decode:true \">public void Foo(int arg)\r\n{\r\n    PrintTheArg();\r\n    return;\r\n    void PrintTheArg()\r\n    {\r\n        Console.WriteLine(arg);\r\n    }\r\n}<\/pre>\n<p>If a local function captures a local variable or an argument then the C# compiler generates a special closure struct, instantiates it and passes it by reference to a generated static method:<\/p>\n<pre class=\"lang:default decode:true \">internal struct c__DisplayClass0_0\r\n{\r\n    public int arg;\r\n}\r\n\r\npublic void Foo(int arg)\r\n{\r\n    \/\/ Closure instantiation\r\n    var c__DisplayClass0_ = new c__DisplayClass0_0() { arg = arg };\r\n    \/\/ Method invocation with a closure passed by ref\r\n    Foo_g__PrintTheArg0_0(ref c__DisplayClass0_);\r\n}\r\n\r\ninternal static void Foo_g__PrintTheArg0_0(ref c__DisplayClass0_0 ptr)\r\n{\r\n    Console.WriteLine(ptr.arg);\r\n}<\/pre>\n<p>(The compiler generate names with invalid characters like <code>&lt;<\/code> and <code>&gt;<\/code>. To improve readability I&#8217;ve changed the names and simplified the code a little bit.)<\/p>\n<p>A local function can capture instance state, local variables (***) or arguments. No heap allocation will happen.<\/p>\n<p>(***) Local variables used in a local function should be definitely assigned at the local function declaration site.<\/p>\n<p>There are few cases when a heap allocation will occur:<\/p>\n<ol>\n<li>A local function is explicitly or implicitly converted to a delegate.<\/li>\n<\/ol>\n<p><strong>Only a delegate allocation<\/strong> will occur if a local function captures static\/instance fields but does not capture locals\/arguments.<\/p>\n<pre class=\"lang:default decode:true \">public void Bar()\r\n{\r\n    \/\/ Just a delegate allocation\r\n    Action a = EmptyFunction;\r\n    return;\r\n    void EmptyFunction() { }\r\n}<\/pre>\n<p><strong>Closure allocation and a delegate allocation<\/strong> will occur if a local function captures locals\/arguments:<\/p>\n<pre class=\"lang:default decode:true \">public void Baz(int arg)\r\n{\r\n    \/\/ Local function captures an enclosing variable.\r\n    \/\/ The compiler will instantiate a closure and a delegate\r\n    Action a = EmptyFunction;\r\n    return;\r\n    void EmptyFunction() { Console.WriteLine(arg); }\r\n}<\/pre>\n<ol start=\"2\">\n<li>A local function captures a local variable\/argument and anonymous function captures variable\/argument from the same scope.<\/li>\n<\/ol>\n<p>This case is way more subtle.<\/p>\n<p>The C# compiler generates a different closure type per lexical scope (method arguments and top-level locals reside in the same top-level scope). In the following case the compiler will generate two closure types:<\/p>\n<pre class=\"lang:default decode:true \">public void DifferentScopes(int arg)\r\n{\r\n    {\r\n        int local = 42;\r\n        Func&lt;int&gt; a = () =&gt; local;\r\n        Func&lt;int&gt; b = () =&gt; local;\r\n    }\r\n\r\n    Func&lt;int&gt; c = () =&gt; arg;\r\n}<\/pre>\n<p>Two different lambda expressions will use the same closure type if they capture locals from the same scope. Lambdas <code>a<\/code> and <code>b<\/code> reside in the same closure:<\/p>\n<pre class=\"lang:default decode:true \">private sealed class c__DisplayClass0_0\r\n{\r\n    public int local;\r\n\r\n    internal int DifferentScopes_b__0()\r\n    {\r\n        \/\/ Body of the lambda 'a'\r\n        return this.local;\r\n    }\r\n\r\n    internal int DifferentScopes_b__1()\r\n    {\r\n        \/\/ Body of the lambda 'a'\r\n        return this.local;\r\n    }\r\n}\r\n\r\nprivate sealed class c__DisplayClass0_1\r\n{\r\n    public int arg;\r\n\r\n    internal int DifferentScopes_b__2()\r\n    {\r\n        \/\/ Body of the lambda 'c'\r\n        return this.arg;\r\n    }\r\n}\r\n\r\npublic void DifferentScopes(int arg)\r\n{\r\n    var closure1 = new c__DisplayClass0_0 { local = 42 };\r\n    var closure2 = new c__DisplayClass0_1() { arg = arg };\r\n    var a = new Func&lt;int&gt;(closure1.DifferentScopes_b__0);\r\n    var b = new Func&lt;int&gt;(closure1.DifferentScopes_b__1);\r\n    var c = new Func&lt;int&gt;(closure2.DifferentScopes_b__2);\r\n}<\/pre>\n<p>In some cases, this behavior can cause some very serious memory-related issues. Here is an example:<\/p>\n<pre class=\"lang:default decode:true \">private Func&lt;int&gt; func;\r\npublic void ImplicitCapture(int arg)\r\n{\r\n    var o = new VeryExpensiveObject();\r\n    Func&lt;int&gt; a = () =&gt; o.GetHashCode();\r\n    Console.WriteLine(a());\r\n\r\n    Func&lt;int&gt; b = () =&gt; arg;\r\n    func = b;\r\n}<\/pre>\n<p>It seems that the <code>o<\/code> variable should be eligible for garbage collection right after the delegate invocation <code>a()<\/code>. But this is not the case. Two lambda expressions share the same closure type:<\/p>\n<pre class=\"lang:default decode:true \">private sealed class c__DisplayClass1_0\r\n{\r\n    public VeryExpensiveObject o;\r\n    public int arg;\r\n\r\n    internal int ImplicitCapture_b__0()\r\n        =&gt; this.o.GetHashCode();\r\n\r\n    internal int ImplicitCapture_b__1()\r\n        =&gt; this.arg;\r\n}\r\n\r\nprivate Func&lt;int&gt; func;\r\n\r\npublic void ImplicitCapture(int arg)\r\n{\r\n    var c__DisplayClass1_ = new c__DisplayClass1_0()\r\n    {\r\n        arg = arg,\r\n        o = new VeryExpensiveObject()\r\n    };\r\n    var a = new Func&lt;int&gt;(c__DisplayClass1_.ImplicitCapture_b__0);\r\n    Console.WriteLine(func());\r\n    var b = new Func&lt;int&gt;(c__DisplayClass1_.ImplicitCapture_b__1);\r\n    this.func = b;\r\n}<\/pre>\n<p>This means that <strong>the lifetime of the closure instance is bound to the lifetime of the <code>func<\/code> field<\/strong>: the closure stays alive until the delegate <code>func<\/code> is reachable from the application. This can prolong the lifetime of the <code>VeryExpensiveObject<\/code> drastically causing, basically, a memory leak.<\/p>\n<p>A similar issue happens when a local function and lambda expression captures variables from the same scope. Even if they capture different variables the closure type will be shared causing a heap allocation:<\/p>\n<pre class=\"lang:default decode:true\">public int ImplicitAllocation(int arg)\r\n{\r\n    if (arg == int.MaxValue)\r\n    {\r\n        \/\/ This code is effectively unreachable\r\n        Func&lt;int&gt; a = () =&gt; arg;\r\n    }\r\n\r\n    int local = 42;\r\n    return Local();\r\n\r\n    int Local() =&gt; local;\r\n}<\/pre>\n<p>Compiles to:<\/p>\n<pre class=\"lang:default decode:true \">private sealed class c__DisplayClass0_0\r\n{\r\n    public int arg;\r\n    public int local;\r\n\r\n    internal int ImplicitAllocation_b__0()\r\n        =&gt; this.arg;\r\n\r\n    internal int ImplicitAllocation_g__Local1()\r\n        =&gt; this.local;\r\n}\r\n\r\npublic int ImplicitAllocation(int arg)\r\n{\r\n    var c__DisplayClass0_ = new c__DisplayClass0_0 { arg = arg };\r\n    if (c__DisplayClass0_.arg == int.MaxValue)\r\n    {\r\n        var func = new Func&lt;int&gt;(c__DisplayClass0_.ImplicitAllocation_b__0);\r\n    }\r\n    c__DisplayClass0_.local = 42;\r\n    return c__DisplayClass0_.ImplicitAllocation_g__Local1();\r\n}<\/pre>\n<p>As you can see all the locals from the top-level scope now become part of the closure class causing the closure allocation even when a local function and a lambda expression captures different variables.<\/p>\n<h4>Local functions 101<\/h4>\n<p>Here is a list of the most important aspects about local functions in C#:<\/p>\n<ol>\n<li>Local functions can define iterators.<\/li>\n<li>Local functions useful for eager validation for async methods and iterator blocks.<\/li>\n<li>Local functions can be recursive.<\/li>\n<li>Local functions are allocation-free if no conversion to delegates is happening.<\/li>\n<li>Local functions are slightly more efficient than anonymous functions due to a lack of delegate invocation overhead (****).<\/li>\n<li>Local functions can be declared after return statement separating main logic from the helpers.<\/li>\n<li>Local functions can &#8220;hide&#8221; a function with the same name declared in the outer scope.<\/li>\n<li>Local functions can be <code>async<\/code> and\/or <code>unsafe<\/code> no other modifiers are allowed.<\/li>\n<li>Local functions can&#8217;t have attributes.<\/li>\n<li>Local functions are not very IDE friendly: there is no &#8220;extract local function refactoring&#8221; (yet) and if a code with a local function is partially broken you&#8217;ll get a lot of &#8220;squiggles&#8221; in the IDE.<\/li>\n<\/ol>\n<p>(****) Here is a benchmark and the results:<\/p>\n<pre class=\"lang:default decode:true \">private static int n = 42;\r\n\r\n[Benchmark]\r\npublic bool DelegateInvocation()\r\n{\r\n    Func&lt;bool&gt; fn = () =&gt; n == 42;\r\n    return fn();\r\n}\r\n\r\n[Benchmark]\r\npublic bool LocalFunctionInvocation()\r\n{\r\n    return fn();\r\n    bool fn() =&gt; n == 42;\r\n}<\/pre>\n<pre class=\"lang:default decode:true \">                  Method |      Mean |     Error |    StdDev |\r\n------------------------ |----------:|----------:|----------:|\r\n      DelegateInvocation | 1.5041 ns | 0.0060 ns | 0.0053 ns |\r\n LocalFunctionInvocation | 0.9298 ns | 0.0063 ns | 0.0052 ns |<\/pre>\n<p>To get this numbers you have to manually \u201cdecompile\u201d a local function to a regular function. The reason for that is simple: such a simple function like \u201cfn\u201d is inlined by the runtime and the benchmark won\u2019t show you real invocation cost. To get these numbers I used a static function marked with <strong>NoInlining<\/strong> attribute (unfortunately, you can\u2019t use attributes with local functions).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Local functions is a new feature in C# 7 that allows defining a function inside another function. When to use a local function? The main idea of local functions is very similar to anonymous methods: in some cases creating a named function is too expensive in terms of cognitive load on a reader. Sometimes [&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-1025","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c","tag-seteplia"],"acf":[],"blog_post_summary":"<p>The Local functions is a new feature in C# 7 that allows defining a function inside another function. When to use a local function? The main idea of local functions is very similar to anonymous methods: in some cases creating a named function is too expensive in terms of cognitive load on a reader. Sometimes [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1025","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=1025"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1025\/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=1025"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=1025"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=1025"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}