I have moved!

I've moved my blog
CLICK HERE

Friday, 13 June 2008

The classic delegate/foreach interaction bug (and a solution)

If you've used C# anonymous delegates or lambdas for a while (or anonymous functions in JavaScript) you will have encountered this problem. You make a delegate for each item in a list, and they all seem to wind up referring to the last item on the list. FUME!

It's just an unfortunate side effect of the way foreach works. It reuses the same loop variable each time around the loop, and so that loop variable is created outside the scope of the loop, and so all the delegates you create inside the loop are actually looking at the same variable, not their own local copies.

This demonstrates the problem, and also gives a neat solution:

static class Extensions
{
 public static void ForEach<T>(this IEnumerable<T> on,
                               Action<T> action)
 {
     foreach (T item in on)
         action(item);
 }
}

class Program
{
 static void Main(string[] args)
 {
     // A list of actions to execute later
     List<Action> actions = new List<Action>();

     // Numbers 0 to 9
     IEnumerable<int> numbers = Enumerable.Range(0, 10);

     // Store an action that prints each number (WRONG!)
     foreach (int number in numbers)
         actions.Add(() => Console.WriteLine(number));

     // Run the actions, we actually print 10 copies of "9"
     foreach (Action action in actions)
         action();

     // So try again
     actions.Clear();

     // Store an action that prints each number (RIGHT!)
     numbers.ForEach(number =>
         actions.Add(() => Console.WriteLine(number)));

     // Run the actions
     foreach (Action action in actions)
         action();
 }
}

By using ForEach (an extension method) instead of using foreach directly, we make the problem disappear, because now each time around the loop we have a unique number variable which is properly captured by the delegates we created.

Notes:

  • The ForEach extension method I define above is actually already available as a method in the List<T> class, so if you're looping over a List<T>, you don't need that extension method.
  • That extension method ought to be added to the System.Linq.Enumerable class, oughtn't it?
  • One situation this can't help with is yield return. If you are looping through a list of items, and then you want to yield return each item, you're out of luck with this solution.

Saturday, 7 June 2008

C++/CLI/WPF

The executive summary of this post is as follows:

Application().Run(%Window());

That line of code is all you need to make a blank window open in today's Visual C++. And if you're a veteran of the dark days of Petzold and Win32, that has to be viewed as a major improvement. (Even if that % operator does look like gibberish.)

In fact from here on in, I'll assume you are such a veteran but are only vaguely aware of .NET.

Win32 API has a native language - C, and by extension, C++. Other languages lack the equivalent of all the .h and .lib files that are the doorway to Win32. Even C# only provides the syntax for declaring entry points, and the user has to then use that syntax to manually declare them (although community efforts like http://pinvoke.net/ have naturally sprung up to fill this gap).

And some APIs require direct manipulation of native memory just to call them. This is notoriously difficult to get right in C and C++. Try the security or Spooler or Lan Manager APIs for example. Of course C# can't really do anything to make it easier, as every case is slightly different, but at least in C++ there is sample code to guide you, and it can be tricky to translate it into the equivalent unsafe C#.

So Visual C++ still has a place in 2008. And then there's legacy code that needs new features. The question is, how easy is it to start from an old-style C++ app and then seamlessly mix today's CLR libraries into it?

To test this in Visual Studio 2008, create a C++ Win32 Console Application. This serves as our example starting point, all old and crummy, and the IDE has written the crummy old main function for us like this:

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

Obviously we can include <windows.h> and do anything we like with Win32. But then we look at Petzold and see how many pages of code are needed just to get a blank window to open on the screen, and we think to ourselves: there must be an easier way.

Go to the project's Properties, and under Configuration Properties change the Common Language Runtime support setting to have the value: Common Language Runtime Support (/clr).

Then right-click the project and choose References. Click Add Reference and choose the following magical ingredients:

  • PresentationCore
  • PresentationFramework
  • WindowsBase

Note that just by adding the references, our C++ language namespace already contains all the types we need. There's no need to include any extra headers. But we can still use a using namespace declaration to help us to abbreviate our code, same as in standard C++. So put this between the #include statement and the _tmain function:

using namespace System::Windows;

(It has to be after the stdafx.h header, because of the weird behaviour of Visual C++ precompiled headers, sigh.)

Directly above the _tmain function, paste this magical incantation:

[System::STAThread]

This is an attribute, and it has to be there for WPF to work. Finally, we're ready to enter a new world! The excitement is electric here at the Stroustrup Stadium.

Put this inside the _tmain function.

Application().Run(%Window());

Now hit F5. A blank window opens! When you close it, the program terminates (in fact, control returns from the Run function, so the Window behaves like a modal dialog box).

As a C++ veteran, you'd assume that Application is either a function that returns an object (or a reference to an object) or else its the constructor of a type, being used here to make a temporary instance. Well, I can tell you it's the latter: constructor of a temporary. Same for the Window type. We construct an Application, construct a Window, and then call Application::Run, passing it... something windowy. If we tweaked the code a little, you'd understand it immediately:

Application().Run(&Window());

The % operator is very much the CLR equivalent of &. As always in C++, we distinguish between an object and a pointer-to-object. When declaring a pointer-like variable, we use ^ instead of * (and we call the variable a handle instead of a pointer, and we use gcnew instead of new to construct a free store instance). It's almost as if a whole separate peer language has been dropped into C++, but the new language still has the characteristic flavour of the old.

So both of these have the same outcome as the original snippet:

Window w;
Application().Run(%w);

or...

Window ^w = gcnew Window();
Application().Run(w);

The analogy even extends to C++ references, which are like pointers that can only be assigned to once and then are syntactically used like objects instead of pointers. For example,

Window ^w = gcnew Window();

Application ^a1 = gcnew Application();
a1->Run(w);

Because a1 is a handle, we have to use the arrow (->) operator to call functions on it, instead of the dot, just like we do with pointers. But just as in standard C++, we can avoid that:

Application ^a1 = gcnew Application();
    
Application %a2 = *a1;
a2.Run(w);

Again, note how in the declarations, ^ is like * and % is like &. But in the usage, the syntax is just like Standard C++: asterisk to dereference, and arrow to access members - this extra bit of uniformity was suggested by Stroustrup to allow templates to be written such that they would work on pointers or handles.

The part I really like is the way destructors work, and I wish C# had the same thing (it's currently only part of the way there, with the using statement). But anyway, to finish off the simple example, add this extra namespace declaration:

using namespace System::Windows::Controls;

Then try this code:

TextBlock b;
b.Text = "Hello, world.";

Window w;
w.Content = %b;
Application().Run(%w);

Here's the complete source:

#include "stdafx.h"

using namespace System::Windows;
using namespace System::Windows::Controls;

[System::STAThread]
int _tmain(int argc, _TCHAR* argv[])
{
    TextBlock b;
    b.Text = "Hello, world.";

    Window w;
    w.Content = %b;
    Application().Run(%w);

    return 0;
}