Wrong compiler warning? Or Not?

This piece of code results in a warning.

   1: class Test

   2: {

   3:     public static void Main()

   4:     {

   5:         object obj = "Senthil";

   6:         string myName = "Senthil";

   7:         Console.WriteLine(obj == myName);

   8:     }

   9: }

The compiler says “warning CS0252: Possible unintended reference comparison; to get a value comparison, cast the left hand side to type ‘string’” on line 7. The compiler is right; it has no way of knowing that obj is actually a string. It infers the static type of obj to be System.Object, and if you’ve done any programming in C# at all, you’ll know that the default behavior of the == operator is reference comparison. This code is unintentionally comparing reference values of two local variables, and that’s what the compiler is warning about.

Yet try running the code, and you’ll see that it works correctly; it prints True. Is the compiler wrong?

No. The code appears to work fine because string interning masks the problem. The C# compiler figures that there are two constant strings in the program, and both are equal, so instead of creating two distinct string objects, it creates only one. With strings being immutable, reusing string objects for identical strings is safe. And that’s why this code works, both obj and myName refer to the same string object, which means reference comparison will succeed.

Now that we know why it’s working, it’s easy to prove that the compiler warning is right with a small code change.

   1: class Test

   2: {

   3:     public static void Main()

   4:     {

   5:         object obj = "Senthil";

   6:  

   7:         string myName1 = "Sen";

   8:         string myName2 = "thil";

   9:         string myName = myName1 + myName2;

  10:         Console.WriteLine(obj == myName);

  11:     }

  12: }

 
Constructing myName dynamically forces the compiler to create another string object; it cannot reuse the interned one. As you’d expect, this piece of code will print False.

Fixing the warning is a mere matter of casting obj to the correct type (string) and then doing the equality check.

   1: class Test

   2: {

   3:     public static void Main()

   4:     {

   5:         object obj = "Senthil";

   6:  

   7:         string myName1 = "Sen";

   8:         string myName2 = "thil";

   9:         string myName = myName1 + myName2;

  10:         Console.WriteLine(((string)obj) == myName);

  11:     }

  12: }

Or we could use the Equals method, which is virtual and won’t be fooled by the compile time type.

   1: class Test

   2: {

   3:     public static void Main()

   4:     {

   5:         object obj = "Senthil";

   6:  

   7:         string myName1 = "Sen";

   8:         string myName2 = "thil";

   9:         string myName = myName1 + myName2;

  10:         Console.WriteLine(obj.Equals(myName));

  11:     }

  12: }

Both of them print True, which is what we want.

When what you set is not what you get : SetEnvironmentVariable and getenv

Mixing SetEnvironmentVariable and getenv is asking for trouble, as we recently found to our dismay (and exasperation!). It took some serious debugging to figure out the actual problem – let’s see if you can figure it out.

Here’s some C++/CLI code that uses getenv to read the value of an environment variable and print it to the console.

   1: public ref class EnvironmentVariablePrinter

   2: {

   3:     public:

   4:         void PrintEnv(String ^key)

   5:         {

   6:              IntPtr ptr = Marshal::StringToHGlobalAnsi(key);

   7:              const char *ckey = (const char *)ptr.ToPointer();

   8:              const char *cval = getenv(ckey);

   9:              string val = cval == NULL ? "" : string(cval);

  10:  

  11:              cout << "Key is " << ckey << " and value is " << val;

  12:  

  13:              Marshal::FreeHGlobal(ptr);    

  14:         }

  15: };

PrintEnv merely converts the .NET string into an unmanaged one and calls getenv, printing the returned value to the console.

And here’s some C# code that tests the class.

   1: class Test

   2: {

   3:     const string key = "MyKey";

   4:     public static void Main()

   5:     {

   6:         Environment.SetEnvironmentVariable(key, "MyValue");

   7:         PrintValue();

   8:     }

   9:  

  10:     private static void PrintValue()

  11:     {

  12:         EnvironmentVariablePrinter er = new EnvironmentVariablePrinter();

  13:         er.PrintEnv(key);

  14:     }

  15: }

The code uses System.Environment.SetEnvironmentVariable to set the value of the variable and then calls the C++/CLI code to verify that it prints the correct value. And of course, being written in different languages, the two pieces of code must reside in different projects, say CPlusPlusLib.dll and ConsoleApplication.exe, with the latter referencing the former.

No surprises here – this works as expected and prints “Key is MyKey and value is MyValue”.

However, a seemingly harmless change breaks the code big time.

   1: class Test

   2: {

   3:     const string key = "MyKey";

   4:     public static void Main()

   5:     {

   6:         Environment.SetEnvironmentVariable(key, "MyValue");

   7:         EnvironmentVariablePrinter er = new EnvironmentVariablePrinter();

   8:         er.PrintEnv(key);

   9:     }

  10: }

All I’ve done is inlining of PrintValue, yet running this code prints “Key is MyKey and value is” – getenv is now returning NULL instead of “MyValue”.

It gets even more interesting.

   1: class Test

   2: {

   3:     const string key = "MyKey";

   4:     public static void Main()

   5:     {

   6:         Environment.SetEnvironmentVariable(key, "MyValue");

   7:         EnvironmentVariablePrinter er = null;

   8:         PrintValue(); 

   9:     }

  10:  

  11:     private static void PrintValue()

  12:     {

  13:         EnvironmentVariablePrinter er = new EnvironmentVariablePrinter();

  14:         er.PrintEnv(key);

  15:     }

  16: }

This doesn’t work either – the mere declaration of EnvironmentVariablePrinter inside Main makes getenv return NULL for “MyKey”. This can’t be good, can it?

Actually yes, because that is a valuable clue – it means the change in behavior has something to do with JITting. As long as all code that references EnvironmentVariablePrinter is in a separate method, everything works fine (in debug mode, atleast). Things start going south when any such code is in Main itself.

What would the JITter do differently in the two scenarios? Load the assembly containing EnvironmentVariablePrinter (CPlusPlusLib.dll) at different times, of course. When all code referencing EnvironmmentVariablePrinter is inside PrintValue, it will have to load the DLL only when JITting PrintValue, whereas in the other case, it will have to load it when JITting Main. JITting Main obviously occurs much before JITting PrintValue, so DLL load time (relative to other code) is one big difference between the two scenarios that occurs because of JITting.

Why would loading CPlusPlusLib.dll a little early make getenv return NULL?

To understand that, you’ll first have to know how the getenv function works. Windows has APIs to set and get environment variables (SetEnvironmentVariable/GetEnvironmentVariable), and the .NET method P/Invokes into the Windows API to set and get values. getenv, on the other hand, is a CRT function, and does not delegate to the Windows API. Instead, the CRT gets all environment variables and their values when it is starting up (using the GetEnvironmentStrings Windows API), and copies them into its own data structures (MSVCR80!environ). getenv then works on the copied data from then on.

Now do you see the problem? When CPlusPlusLib.dll is loaded early (when JITting Main), the CRT also gets loaded as one of its dependencies, and the startup code that copies environment variables runs right away. At that point, Main hasn’t even been JITted yet, so there’s no way our call to System.Environment.SetEnvironmentVariable could have run by that time. And when it actually runs, it’s too late – the CRT environ block would have been updated much earlier, and calling the Windows API’s SetEnvironmentVariable wouldn’t have any effect on the cached values. When getenv runs, it looks in the cached values and returns NULL.

It’s easy to see why it works in the first case now – CRT loading occurs when JITting PrintValue, and that occurs after our call to SetEnvironmentVariable has executed. Which means that when it calls GetEnvironmentStrings as part of startup, it gets the variable (and its value) that we just set.

Nasty, ain’t it? The actual scenario was a lot more messy – things suddenly stopped working when we linked to a DLL ported to VS2008. We actually figured the problem backwards – we first saw that the CRT load time was different, theorized how getenv works, verified the theory by stepping through the assembly code and looking at the environ block, and once we realized the problem, figured out what was causing early loading of the CRT. Windbg was awesome for debugging this – things would have been very difficult if not for sxe ld:MSVCR90 and x MSVCR80!environ.

The fix was rather simple – in our case, we merely had to move code that set environment variable before CRT load. There’s another twist though; mscorwks.dll, which is the heart of the CLR, loads MSVCR80 when it loads, and you can’t set your environment variables before that, not from managed code anyway. Fortunately, in our case, the getenv call is from a library that links to MSVCR90, so as long as we set the environment variable before that version of the CRT loads, we’re good to go. Until the CLR gets linked to MSVCR90, anyway :).

Just Attach

Attach to what? To the process you want to debug, of course.

How many developers attach to and debug arbitrary processes running on their machines? Very few, I’d imagine. And I’d think that even those few people typically prefer Windbg or an equivalent debugger to the one supplied with Visual Studio.

Which means that aside from ASP .NET developers, almost all of us using Visual Studio attach to the application that we are working on and nothing else. To attach

1. You summon the “Attach to Process” dialog by hitting Ctrl + Alt + P. Or if you are a mouse person, you go to Debug –> Attach to Process.

2. You search for your application in the list of processes shown and select it.

3. You optionally change some settings and then hit OK.

The second step can be particularly annoying, especially if the name of your application starts with a particularly common letter that occurs in the latter half of the English alphabet (it’s a tie between ‘s’ and ‘v’ on my machine). Even otherwise, if you’ve worked on the application for a significant amount of time, the keystrokes to select it becomes part of muscle memory (down arrow, down arrow, Enter, for e.g.,), and you occasionally end up attaching to the wrong application because some other process sneaked in. Surely there must be a better way?

Enter JustAttach – a macro that does just that. It finds out the output file path of the startup project of your solution and automatically attaches to it.

The full macro code is at the end of the blog post. You can also download, unzip, open Macro Explorer (View –> Other Windows –> Macro Explorer) and select Load Macro Project to start using it right away.

Do your fingers a favor by binding the command to a VS shortcut (Tools –> Options –> Keyboard, type JustAttach in the textbox and choose a shortcut like Ctrl + Alt+ Y) ; your fingers will thank you for it :).

   1: Imports System

   2: Imports EnvDTE

   3: Imports EnvDTE80

   4: Imports EnvDTE90

   5: Imports System.Diagnostics

   6:  

   7: Public Module SenthilMacros

   8:     Public Sub JustAttach()

   9:         Dim solutionBuild As SolutionBuild = DTE.Solution.SolutionBuild

  10:         Dim startupProjectName As String = solutionBuild.StartupProjects(0)

  11:  

  12:         If String.IsNullOrEmpty(startupProjectName) Then

  13:             MsgBox("Could not attach because the startup project could not be determined", MsgBoxStyle.Critical, "Failed to Attach")

  14:             Return

  15:         End If

  16:  

  17:         Dim startupProject As Project = FindProject(startupProjectName.Trim())

  18:         Dim outputFilePath As String = FindOutputFileForProject(startupProject)

  19:  

  20:         If String.IsNullOrEmpty(outputFilePath) Then

  21:             MsgBox("Could not attach because output file path for the startup project could not be determined", MsgBoxStyle.Critical, "Failed to Attach")

  22:             Return

  23:         End If

  24:  

  25:         Attach(outputFilePath)

  26:     End Sub

  27:     Sub Attach(ByVal file As String)

  28:         Dim process As EnvDTE.Process

  29:  

  30:         For Each process In DTE.Debugger.LocalProcesses

  31:             If process.Name = file Then

  32:                 process.Attach()

  33:                 Return

  34:             End If

  35:         Next

  36:  

  37:         MsgBox("Could not attach because " + file + " is not found in the list of running processes", MsgBoxStyle.Critical, "Failed to Attach")

  38:     End Sub

  39:  

  40:     Function FindProject(ByVal projectName As String) As Project

  41:         Dim project As Project

  42:         For Each project In DTE.Solution.Projects

  43:             If project.UniqueName = projectName Then

  44:                 Return project

  45:             End If

  46:         Next

  47:     End Function

  48:     Function FindOutputFileForProject(ByVal project As Project) As String

  49:         Dim fileName As String = project.Properties.Item("OutputFileName").Value.ToString()

  50:         Dim projectPath As String = project.Properties.Item("LocalPath").Value.ToString()

  51:  

  52:         Dim config As Configuration = project.ConfigurationManager.ActiveConfiguration

  53:         Dim buildPath = config.Properties.Item("OutputPath").Value.ToString()

  54:  

  55:         If String.IsNullOrEmpty(fileName) Or String.IsNullOrEmpty(projectPath) Then

  56:             Return ""

  57:         End If

  58:  

  59:         Dim folderPath As String = System.IO.Path.Combine(projectPath, buildPath)

  60:         Return System.IO.Path.Combine(folderPath, fileName)

  61:  

  62:     End Function

  63: End Module

  64:  

Anonymous methods as event handlers – Part 2

The previous post discussed having anonymous methods as event handlers and ended with a question – why doesn’t unsubscription work while subscription works out alright?

Vivek got the answer spot on – the way the C# compiler handles and translates anonymous methods is the reason.

Here’s the code involved.

   1: public void Initialize()

   2: {

   3:     control.KeyPressed += IfEnabledThenDo(control_KeyPressed);

   4:     control.MouseMoved += IfEnabledThenDo(control_MouseMoved);

   5: }

   6:  

   7: public void Destroy()

   8: {

   9:     control.KeyPressed -= IfEnabledThenDo(control_KeyPressed);

  10:     control.MouseMoved -= IfEnabledThenDo(control_MouseMoved);

  11: }

  12:  

  13: public EventHandler<Control.ControlEventArgs> IfEnabledThenDo(EventHandler<Control.ControlEventArgs> actualAction)

  14: {

  15:     return (sender, args) => { if (args.Control.Enabled) actualAction(sender, args); };

  16: }

The compiler translates IfEnabledThenDo into this

   1: public EventHandler<Control.ControlEventArgs> IfEnabledThenDo(EventHandler<Control.ControlEventArgs> actualAction)

   2: {

   3:     <>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();

   4:     CS$<>8__locals2.actualAction = actualAction;

   5:     return new EventHandler<Control.ControlEventArgs>(CS$<>8__locals2.<IfEnabledThenDo>b__0);

   6: }

Now the problem should be fairly obvious – every time the function is called, a new object gets created, and the event handler returned actually refers to a method (<IfEnabledThenDo>b__0) on the new instance. And that’s what breaks unsubscription. –= will not remove a delegate of a different instance of the same class from the invocation list – if it did, the consequences would not be pleasant if multiple instances of the same class subscribe to an event.

But why does the compiler translate our lambda expression this way? Raymond Chen has a great blog post explaining why, but the short answer is that it is needed to “hold” actualAction (the method parameter to IfEnabledThenDo) so that it is available when the event handler actually executes.

Now that we know why, the way to get around this issue is to cache the delegate instance returned by IfEnabledThenDo and use the same instance for subscription and unsubscription.

   1: EventHandler<Control.ControlEventArgs> keyPressed;

   2: EventHandler<Control.ControlEventArgs> mouseMoved;

   3:  

   4: public void Initialize()

   5: {

   6:    keyPressed = IfEnabledThenDo(control_KeyPressed);

   7:    mouseMoved = IfEnabledThenDo(control_MouseMoved);

   8:  

   9:    control.KeyPressed += keyPressed;

  10:    control.MouseMoved += mouseMoved;

  11: }        

  12:  

  13: public void Destroy()

  14: {

  15:    control.KeyPressed -= keyPressed;

  16:    control.MouseMoved -= mouseMoved;

  17: }

Knowing how things work under the hood has its advantages, I guess 🙂

 

PS : A very small syntactic change to the original example would have made the code work right away. If you’ve followed along this far, you should be able to figure out why.

   1: public void Initialize()

   2: {

   3:    actualAction = control_KeyPressed;

   4:    control.KeyPressed += IfEnabledThenDo();

   5: }        

   6:  

   7: public void Destroy()

   8: {

   9:     control.KeyPressed -= IfEnabledThenDo();

  10: }

  11:  

  12: EventHandler<Control.ControlEventArgs> actualAction;

  13: public EventHandler<Control.ControlEventArgs> IfEnabledThenDo()

  14: {

  15:     return (sender, args) => { if (args.Control.Enabled) actualAction(sender, args); };

  16: }

Anonymous methods as event handlers – Part 1

The syntactic sugar offered by anonymous methods makes them great candidates for writing event handlers; together with smart type inference, they reduce the amount of code written by an order of magnitude.

And that’s without considering the power offered by closures. With event handlers, closures allow you to kind of “stuff” extra parameters into the handler, without changing the actual number of formal parameters. This blog post shows a situation where an anonymous method acting as an event handler makes code simpler, and then goes on to show a gotcha with un-subscription and anonymous methods.

Here’s a simple Control class that fires a bunch of events.

   1: class Control

   2: {

   3:     public class ControlEventArgs : EventArgs

   4:     {

   5:         public Control Control {get;set;}

   6:     }

   7:  

   8:     public bool Enabled { get; set; }

   9:  

  10:     public event EventHandler<ControlEventArgs> KeyPressed;

  11:     public event EventHandler<ControlEventArgs> LeftButtonClicked;

  12:     public event EventHandler<ControlEventArgs> RightButtonClicked;

  13:     public event EventHandler<ControlEventArgs> MouseMoved;

  14: }

Let’s say you’re developing a GUI application with this class, and you want to handle events only if the originating control is visually enabled i.e., Enabled set to true. Pretty reasonable constraint, but tedious to implement, if you go the standard way of adding the check to the start of each of your event handlers.

   1: class GUIApp

   2: {

   3:     public void Initialize()

   4:     {

   5:         Control control = new Control();

   6:         control.KeyPressed += new EventHandler<Control.ControlEventArgs>(control_KeyPressed);

   7:         control.MouseMoved += new EventHandler<Control.ControlEventArgs>(control_MouseMoved);

   8:     }

   9:  

  10:     void control_MouseMoved(object sender, Control.ControlEventArgs e)

  11:     {

  12:         if (e.Control.Enabled)

  13:         {

  14:             /// 

  15:         }

  16:     }

  17:  

  18:     void control_KeyPressed(object sender, Control.ControlEventArgsEventArgs e)

  19:     {

  20:         if (e.Control.Enabled)

  21:         {

  22:             ///

  23:         }

  24:     }

  25: }

With an anonymous method, you could write a far more terse and easy to maintain version

   1: class GUIApp

   2: {

   3:     public void Initialize()

   4:     {

   5:         Control control = new Control();

   6:         control.KeyPressed += IfEnabledThenDo(control_KeyPressed);

   7:         control.MouseMoved += IfEnabledThenDo(control_MouseMoved);

   8:     }

   9:  

  10:     public EventHandler<Control.ControlEventArgs> IfEnabledThenDo(EventHandler<Control.ControlEventArgs> actualAction)

  11:     {

  12:         return (sender, args) => { if (args.Control.Enabled) { actualAction(sender, args); } };

  13:     }

  14:  

  15:     void control_MouseMoved(object sender, Control.ControlEventArgs e)

  16:     {

  17:         ///

  18:     }

  19:  

  20:     void control_KeyPressed(object sender, Control.ControlEventArgs e)

  21:     {

  22:         ///

  23:     }

  24: }

IfEnabledThenDo returns an anonymous function that first checks whether the control is enabled before calling the actual function. The code is much shorter, and the condition is checked only in one place, which makes it easy to modify or add additional logic without having to remember to change every single event handler. Plus, the reads like an English statement – subscribe to the event and if enabled, then do whatever else is necessary.

Great, but unless you are a masochist who revels in littering the code base with hard to reproduce bugs that bomb your app only when demoing to your most important customer, you must, of course, write code to unsubscribe. But there’s no method name to refer to, so you do it the same way as you did when subscribing.

   1: public void Initialize()

   2: {

   3:     control.KeyPressed += IfEnabledThenDo(control_KeyPressed);

   4:     control.MouseMoved += IfEnabledThenDo(control_MouseMoved);

   5: }

   6:  

   7: public void Destroy()

   8: {

   9:     control.KeyPressed -= IfEnabledThenDo(control_KeyPressed);

  10:     control.MouseMoved -= IfEnabledThenDo(control_MouseMoved);

  11: }

This, unfortunately, won’t work – the application will still remain subscribed to those events. Can you figure out why?

Answer and more in the next blog post.

Remoting IEnumerables

You’re writing this really cool and innovative class to calculate the first hundred thousand natural numbers. You think about the API, and you realize that returning an array of the numbers a) might take a long time to complete, and b) is going to cause memory usage to spike up like mad.

So you decide to stream them instead, returning an IEnumerable<T> instance instead of an array. Being a crack C# developer, you use the incredibly powerful yield keyword, rather than rolling your own implementation of the IEnumerable<T> interface.

   1: class MyCoolMathEngine

   2: {

   3:     public IEnumerable<int> GetFirstHundredThousandNaturalNumbers()

   4:     {

   5:         for (int i = 0; i < 100000; ++i)

   6:             yield return i;

   7:     }

   8: }

People start downloading your class and it becomes so popular that they want you to host it in an external service, as a remote component.

Fine, you say, and you pick .NET remoting to provide remote access. You pat yourself on the back for thinking ahead and using an enumerator model – it scales rather nicely. You write the plumbing code to host the class, and with a victorious smile on your lips, you write a test client that instantiates and accesses the method.

Only to find that it crashes with a System.Runtime.Serialization.SerializationException that says a type that you didn’t even write is not marked serializable.

That’s when it hits you, or at least that’s when it hit me, when I was modifying FinalizeTypeFinder to get it load on a different AppDomain.

Because yield return was used, what actually gets back to the caller is an instance of a compiler generated class that implements IEnumerable<int>, and that autogenerated class is not marked serializable. Nor does it derive from MarshalByRefObject, so there’s no way it can be remoted.

The only real solution I can think of is to write a custom implementation of IEnumerable<T>, like we had to do back in the C# 1.1 days. Yet another instance where compiler magic doesn’t quite work out in a particular scenario, I suppose.

Overload resolution and null

My colleague Soundar discovered this rather interesting behavior.

  1: class Test
  2: {
  3:     public static void Main()
  4:     {
  5:         Test test = null;
  6: 
  7:         Console.WriteLine("{0}", test);
  8:         Console.WriteLine("{0}", null);
  9:     }
 10: }

If you run this code, you’ll find that while line 7 prints an empty line, line 8 causes an ArgumentNullException. Note that the test reference is also null, so it should certainly surprise you that the two lines result in different behavior at runtime.

It certainly surprised me enough to make me dig deeper into the reason for the difference. I reasoned that given that the parameter values are identical at runtime, the discrepancy must happen because of a compiler operation – probably method overloading. And sure enough, the two calls resolve to different overloads.

Line 7 resolves to

public static void WriteLine(string format, object arg0);

whereas Line 8 resolves to

public static void WriteLine(string format, params object[] arg);

A peek at the source code using Reflector showed that the second overload throws if arg is null, whereas the first one packs arg0 into an object array and calls the second overload.

Ok, but why did the compiler pick different overloads?

Intuitively, for a method call with a single parameter, you’d expect the overload resolution algorithm to choose a single parameter method over a method with variable number of arguments. And that’s what the compiler did on line 7.

On line 8, the situation is different – null is directly assignable to arg0 and to arg. The overload resolution algorithm had to choose the best function, and it chose the one with the object array.

That appears counter intuitive, until you have code like

  1: class Test
  2: {
  3:     public static void Main()
  4:     {
  5:         SubTest subTest = null;
  6:         M(subTest);
  7:     }
  8: 
  9:     static void M(Test t) { Console.WriteLine("Test"); }
 10:     static void M(SubTest s) { Console.WriteLine("SubTest"); }
 11: }
 12: 
 13: class SubTest : Test { }

You wouldn’t be surprised if the call at line 6 resolved to M(SubTest), would you?

The C# spec’s rules for determining the best match say that

“ Given an implicit conversion C1 that converts from a type S to a type T1, and an implicit conversion C2 that converts from a type S to a type T2, the better conversion of the two conversions is determined as follows:

  • If T1 and T2 are the same type, neither conversion is better.
  • If S is T1, C1 is the better conversion.
  • If S is T2, C2 is the better conversion.
  • If an implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists, C1 is the better conversion.
  • If an implicit conversion from T2 to T1 exists, and no implicit conversion from T1 to T2 exists, C2 is the better conversion.
  • … “

In this case, SubTest (T1) is implicitly convertible to Test (T2), and therefore the compiler picks M(SubTest).

Now in our case, the compiler was trying to pick the best conversion between null to object and null to object[]. Applying the same rule as above, object[] is implicitly convertible to object, and therefore the overload resolution algorithm chose  WriteLine(string format, params object[] arg). The params modifier didn’t play a part in overload resolution in this (null) case.

Interesting, ain’t it?

Volatile and local

If you’ve done any multithreading programming at all, you must be aware of the volatile modifier. When a field is marked volatile, it tells

1. the JIT compiler that it can’t hoist the field because it may be modified by multiple threads

2. the CLR that the field must be read to and written from with acquire and release semantics.

Given what you’ve read above, the post’s title doesn’t make sense. A local variable, by definition, cannot be accessed from multiple threads. An object referred to by a local variable can be shared among threads, but never the variable itself.

Well, that was true as long as local variables remained just that – local variables. The 2.0 release of C# brought closures to the language, and C# implements capturing of local variables by making them members of a generated class. Now do you see the problem?

  1: public static void Main()
  2: {
  3:     bool stopRunning = false;
  4: 
  5:     Thread t = new Thread(() =>
  6:         {
  7:             while (!stopRunning)
  8:                 Console.WriteLine("Hello");
  9:         });
 10:     t.Start();
 11:     DoSomethingElse();
 12:     stopRunning = true;
 13: }

Nothing out of the ordinary here – I’m creating a thread, passing a lambda to the Thread constructor, and capturing stopRunning inside the lambda.

This code isn’t correct though – for the reasons mentioned in the initial paragraph of this post, stopRunning needs to be declared with the volatile modifier. Unfortunately, you can’t make stopRunning volatile – the compiler complains that local variables cannot be marked volatile.

Oops.

Making stopRunning a member of the class will solve the immediate problem – you can then mark the field volatile, and all is good. However, left at that, it now makes the class non-threadsafe – two threads could call Main, and stopRunning will be shared between them.

I guess this is the price to pay for compiler magic – magic that enables seamless access to local variables from anonymous methods.

For each method in file

ForEachMethodInFile is a Visual Studio macro that lets you do custom actions for each method defined in the current file. I’ve used it in the past to generate logging code to log the start and end of each method, to generate default error handling code etc..  And today someone over at CodeProject wanted to generate a breakpoint at the start of each method. The common thread here is the performing of some custom action for each method in the current file. I figured it would be useful for a lot of people if the “for each method in file” logic is available as a separate library, and that is what is ForEachMethodInFile.

The macro project is available here. To provide a custom action, all you have to do is create a new macro project, and do

  1: Imports System
  2: Imports EnvDTE
  3: Imports EnvDTE80
  4: Imports EnvDTE90
  5: Imports System.Diagnostics
  6: Imports ForEachMethodInFile
  7: 
  8: Public Module BreakOnEachMethodEntry
  9: 
 10:     Public Sub Run()
 11:         ForEachMethod.DoAction(AddressOf AddBreakPoint)
 12:     End Sub
 13: 
 14:     Function AddBreakPoint(ByVal method As CodeFunction)
 15:         DTE.Debugger.Breakpoints.Add(method.Name)
 16:     End Function
 17: 
 18: End Module

You define a callback function that takes the COM object representing a method as a parameter, and then pass on the function to the DoAction method. Your function will be called for each method defined in the file, and the cursor will be positioned at the start of the method before the callback occurs. In this case, I want to add a breakpoint, so I call the appropriate DTE method, passing the current method’s name to tell it where to place the breakpoint.

Here’s the entire code in the ForEachMethodInFile project – it basically recursively traverses code elements in the file, and invokes the callback when it runs into a method.

  1: Imports System
  2: Imports EnvDTE
  3: Imports EnvDTE80
  4: Imports System.Diagnostics
  5: 
  6: Public Module ForEachMethod
  7: 
  8:     Public Sub DoAction(ByRef action As Action(Of CodeFunction))
  9:         ProcessFile(action)
 10:     End Sub
 11: 
 12:     Function ProcessFile(ByRef action As Action(Of CodeFunction))
 13:         Dim selection As EnvDTE.TextSelection
 14:         Dim projectItem As ProjectItem
 15:         Dim fileCodeModel As FileCodeModel
 16:         Dim codeElement As CodeElement
 17:         Dim i As Integer
 18: 
 19:         Dim currentFunction As CodeFunction
 20: 
 21:         projectItem = DTE.ActiveDocument.ProjectItem
 22: 
 23:         fileCodeModel = projectItem.FileCodeModel
 24:         For i = 1 To fileCodeModel.CodeElements.Count
 25:             codeElement = fileCodeModel.CodeElements.Item(i)
 26:             ProcessCodeElement(codeElement, action)
 27:         Next
 28: 
 29:         ' Reformat the modified code
 30:         selection = DTE.ActiveDocument.Selection
 31:         selection.SelectAll()
 32:         selection.SmartFormat()
 33:     End Function
 34: 
 35:     Sub ProcessNamespace(ByVal namespaceElement As CodeNamespace, ByRef action As Action(Of CodeFunction))
 36:         Dim i As Integer
 37:         Dim codeElement As CodeElement
 38: 
 39:         For i = 1 To namespaceElement.Members.Count
 40:             codeElement = namespaceElement.Members.Item(i)
 41:             ProcessCodeElement(codeElement, action)
 42:         Next
 43:     End Sub
 44: 
 45:     Sub ProcessCodeElement(ByVal codeElement As CodeElement, ByRef action As Action(Of CodeFunction))
 46:         If codeElement.Kind = vsCMElement.vsCMElementNamespace Then
 47:             ProcessNamespace(codeElement, action)
 48:         ElseIf codeElement.Kind = vsCMElement.vsCMElementClass Then
 49:             ProcessType(codeElement, action)
 50:         ElseIf codeElement.Kind = vsCMElement.vsCMElementFunction Then
 51:             ProcessMethod(codeElement, action)
 52:         End If
 53:     End Sub
 54: 
 55:     Sub ProcessType(ByVal typeElement As CodeClass, ByRef action As Action(Of CodeFunction))
 56:         Dim i As Integer
 57:         Dim codeElement As CodeElement
 58: 
 59:         For i = 1 To typeElement.Members.Count
 60:             codeElement = typeElement.Members.Item(i)
 61:             If codeElement.Kind = vsCMElement.vsCMElementFunction Then
 62:                 ProcessMethod(codeElement, action)
 63:             ElseIf codeElement.Kind = vsCMElement.vsCMElementClass Then
 64:                 ProcessType(codeElement, action)
 65:             End If
 66:         Next
 67:     End Sub
 68: 
 69:     Sub ProcessMethod(ByVal methodElement As CodeFunction, ByRef action As Action(Of CodeFunction))
 70:         Dim selection As EnvDTE.TextSelection
 71:         Dim editPoint As EnvDTE.EditPoint
 72:         Dim verifyPoint As EnvDTE.TextPoint
 73:         Dim endPointAbsCharOffset As Integer
 74:         Dim column As Integer
 75:         Dim methodRunNotifierSignature As String
 76:         Dim functionStartCode As String
 77:         Dim functionEndCode As String
 78:         Dim parameters As String
 79:         Dim parameter As EnvDTE80.CodeParameter2
 80:         Dim i As Integer
 81: 
 82:         If methodElement.MustImplement Then
 83:             Return
 84:         End If
 85: 
 86:         selection = DTE.ActiveDocument.Selection
 87:         editPoint = selection.ActivePoint.CreateEditPoint()
 88:         verifyPoint = selection.ActivePoint.CreateEditPoint()
 89: 
 90:         ' Move to start of method
 91:         editPoint.MoveToPoint(methodElement.GetStartPoint(vsCMPart.vsCMPartBody))
 92:         selection.MoveToPoint(editPoint)
 93:         verifyPoint.MoveToPoint(methodElement.GetStartPoint(vsCMPart.vsCMPartBody))
 94: 
 95:         action(methodElement)
 96: 
 97:     End Sub
 98: End Module
 99: 
100: 

WinMacro 2.0 beta released

WinMacro is a tiny little application that can record and replay keyboard and mouse actions that you do on your Windows desktop. It’s similar to the macro facility in Word and Excel, but works across applications.

I wrote the initial version nearly 5 years back, and it proved to be very popular, with approximately 30000 downloads and tons of email from users. Most of the emails were appreciative, and some of them touching, especially those that described how WinMacro was helping people do a better job in fields ranging from cancer research to network testing.

There were quite a few feature requests and bug reports too. WinMacro 2.0 (Beta) (http://winmacro.codeplex.com/) attempts to addresses some of them. The list of new features is available in the download page.

That apart, it was “interesting” to look at code I’d written 5 years ago. I found it positively revolting, to say the least. Lots of copy pasted code, no error handling and plenty of global variables and convoluted code made it scored very heavily in the WTF scale. And this was code I was rather proud of, at that time.

On the flip side, the fact that I found my old code disgusting means I’ve improved my coding skills enough to make that code look terrible. But that is still relative improvement though, it remains to be seen how much I score on the absolute WTF scale, if there is one 🙂