{"id":6053,"date":"2007-05-25T17:03:00","date_gmt":"2007-05-25T17:03:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2007\/05\/25\/closures-in-vb-part-3-scope\/"},"modified":"2024-07-05T14:46:24","modified_gmt":"2024-07-05T21:46:24","slug":"closures-in-vb-part-3-scope","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/closures-in-vb-part-3-scope\/","title":{"rendered":"Closures in VB Part 3: Scope"},"content":{"rendered":"<p>Jared here again.&nbsp; For previous articles in this series please see<\/p>\n<ul>\n<li><a href=\"http:\/\/blogs.msdn.com\/vbteam\/archive\/2007\/05\/02\/closures-in-vb-part-1.aspx\">Part 1: Introduction<\/a>\n<li><a href=\"http:\/\/blogs.msdn.com\/vbteam\/archive\/2007\/05\/03\/closures-in-vb-part-2-method-calls.aspx\">Part 2: Method Calls<\/a><\/li>\n<\/ul>\n<p>Thus far in the series we&#8217;ve only lifted variables that are declared in the same block\/scope.&nbsp;What happens if we lift variables in different scope?&nbsp; The answer is that one closure class will be created for every unique scope where a lifted variable is declared and all of the variables in that scope that are lifted will be placed in that closure.&nbsp; Once again, examples speak best<\/p>\n<pre>    <span>Sub<\/span> Scope1()\n        <span>Dim<\/span> x = <span>5<\/span>\n        <span>Dim<\/span> f1 = <span>Function<\/span>(<span>ByVal<\/span> z <span>As<\/span> <span>Integer<\/span>) x + z\n        Console.WriteLine(f1(<span>5<\/span>))\n        <span>If<\/span> x &gt; <span>2<\/span> <span>Then<\/span>\n            <span>Dim<\/span> y = <span>6<\/span>\n            <span>Dim<\/span> g = <span>7<\/span>\n            <span>Dim<\/span> f2 = <span>Function<\/span>(<span>ByVal<\/span> z <span>As<\/span> <span>Integer<\/span>) z + y + g\n            Console.WriteLine(f2(<span>4<\/span>))\n        <span>End<\/span> <span>If<\/span>\n    <span>End<\/span> <span>Sub<\/span><\/pre>\n<p>The code will end up looking like so &#8230;<\/p>\n<pre>    <span>Class<\/span> Closure1\n        <span>Public<\/span> x <span>As<\/span> <span>Integer<\/span>\n        <span>Function<\/span> Lambda_f1(<span>ByVal<\/span> z <span>As<\/span> <span>Integer<\/span>)\n            <span>Return<\/span> x + z\n        <span>End<\/span> <span>Function<\/span>\n    <span>End<\/span> <span>Class<\/span>\n    <span>Class<\/span> Closure2\n        <span>Public<\/span> y <span>As<\/span> <span>Integer<\/span>\n        <span>Public<\/span> g <span>As<\/span> <span>Integer<\/span>\n        <span>Function<\/span> Lambda_f2(<span>ByVal<\/span> z <span>As<\/span> <span>Integer<\/span>)\n            <span>Return<\/span> y + z + g\n        <span>End<\/span> <span>Function<\/span>\n    <span>End<\/span> <span>Class<\/span>\n    <span>Sub<\/span> Scope1()\n        <span>Dim<\/span> c1 <span>As<\/span> <span>New<\/span> Closure1()\n        c1.x = <span>5<\/span>\n        Console.WriteLine(c1.Lambda_f1(<span>5<\/span>))\n        <span>If<\/span> c1.x &gt; <span>2<\/span> <span>Then<\/span>\n            <span>Dim<\/span> c2 <span>As<\/span> <span>New<\/span> Closure2()\n            c2.y = <span>6<\/span>\n            c2.g = <span>7<\/span>\n            Console.WriteLine(c2.Lambda_f2(<span>4<\/span>))\n        <span>End<\/span> <span>If<\/span>\n    <span>End<\/span> <span>Sub<\/span><\/pre>\n<p>There are a couple of items to take away from this example.&nbsp; <\/p>\n<ol>\n<li>Only two closure classes were created even though three variables were lifted.&nbsp; The number of closures only depends on the number of scopes of all of the lifted declared variables.\n<li>The closures are created at the begining of the scope they are associated and not at the begining of the method.&nbsp; This will be more important in the next part of the series.\n<li>Each lambda instance is attached to the closure associated with the scope the lambda is declared in.&nbsp; <\/li>\n<\/ol>\n<p>The next&nbsp;twist is what were to happen if&nbsp;the lambda &#8220;f2&#8221; were to also use the variable &#8220;x&#8221;.&nbsp; As it&#8217;s currently written there is no association between Closure1 and Closure2 therefore&nbsp;there is no way for it to access the lifted variable.&nbsp; The answer is two fold.&nbsp;&nbsp;Firstly to&nbsp;reduce clutter I pasted the closure classes as if they were separate entries.&nbsp; In fact Closure2 would appear as a nested class of Closure1 in the real generated code.&nbsp; <\/p>\n<p>Secondly if x were used inside of &#8220;f2&#8221;, the real use would be &#8220;c1.x&#8221;.&nbsp; That&#8217;s (almost) no different than &#8220;someOtherVar.x&#8221;.&nbsp; Therefore the instance of c1 will be lifted into Closure2.&nbsp; <\/p>\n<pre><span>Dim<\/span> f2 = <span>Function<\/span>(<span>ByVal<\/span> z <span>As<\/span> <span>Integer<\/span>) z + y + g + x<\/pre>\n<p>Woud result in the following definition of Closure2 &#8230;<\/p>\n<pre>    <span>Class<\/span> Closure2\n        <span>Public<\/span> y <span>As<\/span> <span>Integer<\/span>\n        <span>Public<\/span> g <span>As<\/span> <span>Integer<\/span>\n        <span>Public<\/span> c1 <span>As<\/span> Closure1\n        <span>Function<\/span> Lambda_f2(<span>ByVal<\/span> z <span>As<\/span> <span>Integer<\/span>)\n            <span>Return<\/span> y + z + g + c1.x\n        <span>End<\/span> <span>Function<\/span>\n    <span>End<\/span> <span>Class<\/span><\/pre>\n<p>In deeply nested lambdas and scopes this type of lifting will continue recursively.&nbsp; <\/p>\n<p>That&#8217;s it for this entry, the next article will talk about looping structures and possibly variable lifetime.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jared here again.&nbsp; For previous articles in this series please see Part 1: Introduction Part 2: Method Calls Thus far in the series we&#8217;ve only lifted variables that are declared in the same block\/scope.&nbsp;What happens if we lift variables in different scope?&nbsp; The answer is that one closure class will be created for every unique [&hellip;]<\/p>\n","protected":false},"author":260,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[192,195],"tags":[78,94,117],"class_list":["post-6053","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-featured","category-visual-basic","tag-jared-parsons","tag-linqvb9","tag-orcas"],"acf":[],"blog_post_summary":"<p>Jared here again.&nbsp; For previous articles in this series please see Part 1: Introduction Part 2: Method Calls Thus far in the series we&#8217;ve only lifted variables that are declared in the same block\/scope.&nbsp;What happens if we lift variables in different scope?&nbsp; The answer is that one closure class will be created for every unique [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6053","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/260"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=6053"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/6053\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=6053"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=6053"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=6053"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}