
{"id":491,"date":"2010-05-14T14:02:17","date_gmt":"2010-05-14T18:02:17","guid":{"rendered":"http:\/\/www.ikriv.com\/blog\/?p=491"},"modified":"2010-05-14T14:02:17","modified_gmt":"2010-05-14T18:02:17","slug":"c-trouble-with-lambdas-in-for-loops","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=491","title":{"rendered":"C#: Trouble with Lambdas in For Loops"},"content":{"rendered":"<p>I had an interesting bug the other day. I wrote a foreach loop along these lines:<\/p>\n<div style=\"font-family: Courier New; font-size: 10pt; color: black; background: white;\">\n<p style=\"margin: 0px;\"><span style=\"color: blue;\">foreach<\/span> (<span style=\"color: blue;\">var<\/span> entry <span style=\"color: blue;\">in<\/span> controlsByName)<\/p>\n<p style=\"margin: 0px;\">{<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; entry.Key.SomeEvent += (sender,args)=&gt;{ProcessControlName(entry.Value);}<\/p>\n<p style=\"margin: 0px;\">}<\/p>\n<\/div>\n<p>Looks innocent enough, right? There is a big catch here. In functional languages we are accustomed to the fact that everything is immutable. I subconsciously transferred this notion to C# lambdas. I thought that the lambdas capture outer variables <i>by value<\/i> and carry this immutable value with them forever. <b>This is wrong!<\/b>.<\/p>\n<p>C# language specification (found at <code>C:\\Program Files\\Microsoft Visual Studio 9.0\\VC#\\Specifications<\/code> if you have Visual Studio 2008) states in paragraph 7.14.4 that outer variables are captured <i>by reference<\/i>. They don&#8217;t use these exact words, but that&#8217;s the idea. If you change the value of the variable, all lambdas that captured it will be affected.<\/p>\n<p>Even more surprisingly, there will be only one copy of the loop variable such as <code>entry<\/code> above, and all lambdas will share this single copy. This means that the code above has a bug. After the loop has finished, if <code>SomeEvent<\/code> is fired by one of the controls, the name passed to <code>ProcessControlName()<\/code> <font color=\"red\"><b>will always be the name of the last control<\/b><\/font>, regardless of which control fired the event!<\/p>\n<p>It turns out, you can even exploit this variable sharing making lambdas to communicate like this:<\/p>\n<div style=\"font-family: Courier New; font-size: 10pt; color: black; background: white;\">\n<p style=\"margin: 0px;\"><span style=\"color: blue;\">private<\/span> <span style=\"color: blue;\">void<\/span> GetTangledLambdas(<span style=\"color: blue;\">out<\/span> <span style=\"color: #2b91af;\">Func<\/span>&lt;<span style=\"color: blue;\">int<\/span>&gt; getter, <span style=\"color: blue;\">out<\/span> <span style=\"color: #2b91af;\">Action<\/span>&lt;<span style=\"color: blue;\">int<\/span>&gt; setter)<\/p>\n<p style=\"margin: 0px;\">{<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; <span style=\"color: blue;\">int<\/span> x = 0;<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; getter = () =&gt; x;<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; setter = v =&gt; {x = v;};<\/p>\n<p style=\"margin: 0px;\">}<\/p>\n<p style=\"margin: 0px;\">&nbsp;<\/p>\n<p style=\"margin: 0px;\">[<span style=\"color: #2b91af;\">TestMethod<\/span>]<\/p>\n<p style=\"margin: 0px;\"><span style=\"color: blue;\">public<\/span> <span style=\"color: blue;\">void<\/span> Lambads_Can_Communicate_Through_Captured_Variable()<\/p>\n<p style=\"margin: 0px;\">{<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; <span style=\"color: #2b91af;\">Func<\/span>&lt;<span style=\"color: blue;\">int<\/span>&gt; getter;<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; <span style=\"color: #2b91af;\">Action<\/span>&lt;<span style=\"color: blue;\">int<\/span>&gt; setter;<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; GetTangledLambdas(<span style=\"color: blue;\">out<\/span> getter, <span style=\"color: blue;\">out<\/span> setter);<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; setter(10);<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; <span style=\"color: #2b91af;\">Assert<\/span>.AreEqual(10, getter());<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; setter(20);<\/p>\n<p style=\"margin: 0px;\">&nbsp;&nbsp;&nbsp; <span style=\"color: #2b91af;\">Assert<\/span>.AreEqual(20, getter());<\/p>\n<p style=\"margin: 0px;\">}<\/p>\n<\/div>\n<p>This, of course, is not even close to functional programming, even though it uses lambdas \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I had an interesting bug the other day. I wrote a foreach loop along these lines: foreach (var entry in controlsByName) { &nbsp;&nbsp;&nbsp; entry.Key.SomeEvent += (sender,args)=&gt;{ProcessControlName(entry.Value);} } Looks innocent enough, <a href=\"https:\/\/ikriv.com\/blog\/?p=491\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[8,4],"tags":[],"class_list":["entry","author-ikriv","post-491","post","type-post","status-publish","format-standard","category-cs","category-hack"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/491","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=491"}],"version-history":[{"count":0,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/491\/revisions"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=491"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=491"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=491"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}