When being lazy is (finally) good

In this blog post I want to talk about .NET 4 new Lazy<T> class. First of all, why would you need something called Lazy?

You can use it for data access for example; when you load a row from a database parent table. Would you need to load the child rows automatically, or delay until they’re required. Some systems will delay load automatically, or load all they can (but what then when the child rows have other relations to grandchild rows, etc…). This kind of delayed loading of data is just what Lazy<T> (or Lazy(Of T) when using VB.NET) supports.

It’s a great type to use when you have an object which is very expensive to create, and you only want to create it on first use.

Let’s start with an example; let’s say you have this big-ass class:

   1: class BigAndExpensive
   2: {
   3:   string s = "";
   4:  
   5:   public string GetTheData()
   6:   { 
   7:     return s; 
   8:   }
   9:  
  10:   public BigAndExpensive()
  11:   {
  12:     Console.WriteLine("BigAndExpensive is being created...");
  13:     for (int i = 0; i < 10000; i++)
  14:       s = s + ".";
  15:     Console.WriteLine("BigAndExpensive is finally created...");
  16:   }
  17: }

As you can see, creating is very expensive (it will actually consume about 10 Gb of memory, triggering a lot of garbace collects).

Let’s create an instance of this class without, then with Lazy<T> and look at the performance:

   1: BigAndExpensive be;
   2: Lazy<BigAndExpensive> lbe;
   3:  
   4: using (new MeasureDuration("Not using Lazy evaluation"))
   5: {
   6:   be = new BigAndExpensive();
   7: }
   8: using (new MeasureDuration("Accessing non-lazy object's method"))
   9: {
  10:   string s = be.GetTheData();
  11: }
  12: using (new MeasureDuration("Using Lazy evaluation"))
  13: {
  14:   lbe = new Lazy<BigAndExpensive>(false);
  15: }
  16: using (new MeasureDuration("Accessing lazy object's method"))
  17: {
  18:   string s = lbe.Value.GetTheData();
  19: }
  20: using (new MeasureDuration("Again accessing lazy object's method"))
  21: {
  22:   string s = lbe.Value.GetTheData();
  23: }

In order to use the Lazy<T> object you have to get it’s value property. When the lazy loaded value hasn’t yet been created, accessing the Value will create it.

The MeasureDuration class is a little timer taking advantage of the using statement:

   1: class MeasureDuration : IDisposable
   2: {
   3:   Stopwatch sw;
   4:   string what;
   5:  
   6:   public MeasureDuration(string what)
   7:   {
   8:     this.what = what;
   9:     sw = new Stopwatch();
  10:     sw.Start();
  11:   }
  12:  
  13:   public void Dispose()
  14:   {
  15:     sw.Stop();
  16:     Console.WriteLine("Measured duration of -{0}- took {1} ticks ({2} ms)"
  17:                      , what, sw.ElapsedTicks, sw.ElapsedMilliseconds);
  18:   }
  19:  
  20: }

The output I get on machine looks like this:

image

As you can see, creating a Lazy object is very fast, but of course as you can expect, using it the first time is just as expensive due to the creating process. Using it the second time is again very fast.

Now go back to the code, and look for the Lazy<T> constructor. Change the false argument to true:

   1: lbe = new Lazy<BigAndExpensive>(true);

This will make the instantiation process of the actual instance thread-safe. This means it will be a little slower, but only during construction. Is it worth the price? If you’re using multiple threads YES YES YES!

Now let’s try to see what happens when many threads access an unprotected Lazy object (never be lazy AND unprotected :))

This is the code:

   1: private static void UsingLazyObjectsFromMultipleThreads()
   2: {
   3:   Lazy<BigAndExpensive> createMeOncePlease = new Lazy<BigAndExpensive>(isThreadSafe:false);
   4:  
   5:   ManualResetEvent youMayBegin = new ManualResetEvent(false);
   6:   AutoResetEvent done = new AutoResetEvent(false);
   7:  
   8:   // create a lot of threads that will use our object all at once
   9:   for (int i = 0; i < 20; i++)
  10:   {
  11:     Thread t = new Thread(() =>
  12:       {
  13:         youMayBegin.WaitOne();
  14:         Console.WriteLine("Thread {0} getting data", Thread.CurrentThread.ManagedThreadId);
  15:         using (new MeasureDuration("Multithreading"))
  16:           createMeOncePlease.Value.GetTheData();
  17:         done.Set();
  18:       });
  19:     t.Start();
  20:   }
  21:   youMayBegin.Set();
  22:   // wait for all threads to complete
  23:   for (int i = 0; i < 20; i++)
  24:     done.WaitOne();
  25:  
  26: }

I’ve now used the named argument feature of C# 4.0. In this case it make the code a lot clearer doesn’t it?

So what does the code do. It creates 20 threads which all first wait for the “youMayBegin” event. This way all threads will start running at the same time. Then they each access the “createMeOncePlease” lazy instance, so some of them will start to create the instance (because it hasn’t yet been created). Then they will all signal that they’re done so the main thread can stop too.

So let’s run the code (making sure the isThreadSafe is set to false). I get this:

image

This is bad. Very bad. Instead of calling the constructor of my very expensive object once, it calls it several times. why?

Think about lazy’s possible thread-unsafe implementation:

   1: class Lazy<T> where T : class, new()
   2: {
   3:   T instance = null;
   4:  
   5:   public T Value
   6:   {
   7:     get
   8:     {
   9:       if (instance == null)
  10:         instance = new T();
  11:       return instance;
  12:     }
  13:   }
  14: }

When you run the if statement on multiple thread, each will evaluate to true, then each will create an object and overwrite instance’s value.

So what is the solution? Simply pass true for the isThreadSafe argument.

Running this code once more looks like this on my machine:

image

Good. My expensive object only get’s created once. But why are the calls soo expensive after all. That is because when we access Value, only one thread will be allowed to create the instance, but the other Value calls will need to wait for the first one to complete. If you insert another call using Value you’ll see the speed is very fast.

If you only need initialization to be thread-safe, or only access to the object in a thread-safe you you can also use the contructor taking a LazyThreadSafetyMode enumeration:

   1: None = 0,
   2: PublicationOnly = 1,
   3: ExecutionAndPublication = 2

What if your expensive class requires special construction, like a special constructor? Then you can use another constructor of Lazy<T>, one that takes a delegate( Func<T> ) so you can create your object your way.

   1: Lazy<BigAndExpensive> createMeOncePlease = 
   2:   new Lazy<BigAndExpensive>(() => new BigAndExpensive());

IntelliSense improvements in Visual Studio 2010

What developer today can live without intelli-sense? Of course I mean developers who have used intelli-sense before (if you don’t know something how can you miss something?). However finding a member in Visual Studio 2008 requires you to know the first letters of the class/method/… I’m quite sure you sometimes now a class contains a certain word, but can’t remember the beginning.

Now the new and improved intelli-sense in Visual Studio 2010 allows you to see any member containing a certain substring. For example when you type “opt”, you’ll get this:

image

But it even gets better. Try typing “AD”. Because .NET uses Pascal casing for all members, when you type the capital letters it will show you which members contain these same capital letters (and same order):

image

Love it! This also works in other places, for example in the Navigate To window!

With following code,

   1: class WebDeveloper
   2: {
   3: }
   4:  
   5: class Program
   6: {
   7:  
   8:  
   9:   static void Main(string[] args)
  10:   {
  11:     WebDeveloper dev1 = new WebDeveloper();
  12:  
  13:   }
  14: }

opening the Navigate To window (use Ctrl-comma for example, and typing WD in the search box will show like this:

image

Oh, and selecting the WebDeveloper class will automatically highlight every other use of it:

image

Cool!

And don’t you hate it when you start typing a method name you haven’t declared yet. By default Visual Studio will list a couple of suggestions, and when you commit (by pressing space of “(“) Visual studio inserts its own suggestion (and then you need to Undo (Ctrl-Z) to make Visual Studio keep whatever you were typing.

So for example, when you have a variable s of type string, and then you type s.c intelli-sense will show the following. If you now press space, by default you’ll get s.Clone.

image

But now you have auto-completion suggestion mode. In this case Visual Studio will not insert its own suggestion, but will keep your typing instead.

If you do want to insert the suggested method, simply press TAB instead of space of open bracket. From now on this will be my default mode of working…

Gated Check In with Multiple Build Definitions

As promised in my previous blog on Gated Check In, in this blog I’ll discuss using multiple builds with gated check in.

So what happens when you check in (using gated check in) and there are multiple build definitions targeting the solution? Well, Gated Check In will then allow you to choose between the different build definitions; for the moment Team Build does not allow you to filter the build definitions that are shown:

image

In my example I’ve created a second build definition that doesn’t run tests, so you can select this one when you need to check in code without running tests…

Never break a build again with the new Gated Check-in feature from Visual Studio Team System 2010

Breaking the current team build is not a good thing. This will cause many people to lose time while the build is being fixed. So how can you avoid this? One way is by only checking-in on isolated branches, which allow you first to test if everyone’s changes build together.

But, remember that Team System Source Control has that one-click branching feature, called shelving? Well, now if you check in VSTS can take your changeset and merge it on a shelve with the current version in source control. It will then launch a build (using Team Build) and if this is a successful build (depends on the build) will allow you to check-in.

Let’s have a look at this:

To try this you first have to have something in Source Control. For example this simple library project and class:

   1: namespace Lib
   2: {
   3:   public class Code
   4:   {
   5:     public int Test(int i, int j)
   6:     {
   7:       return i + j;
   8:     }
   9:   }
  10: }

I’ve also added two unit tests in a test project:

   1: [TestMethod()]
   2: public void Test_2And3_Returns5()
   3: {
   4:   Code target = new Code(); 
   5:   int i = 2;
   6:   int j = 3;
   7:   int expected = 5;
   8:  
   9:   int actual;
  10:   actual = target.Test(i, j);
  11:   Assert.AreEqual(expected, actual);
  12: }
  13:  
  14: [TestMethod()]
  15: public void Test2And4Returns10()
  16: {
  17:   Code target = new Code();
  18:   int i = 2; 
  19:   int j = 4; 
  20:   int expected = 6; 
  21:   int actual;
  22:   actual = target.Test(i, j);
  23:   Assert.AreEqual(expected, actual);
  24: }

Make sure all of this is currently checked in.

Now go to Team Explorer, right-click on Builds and choose “New Build Definition…” The Build Definition dialog should open. Call your build GatedCheckIn (although the name doesn’t matter, I’ll be using it later).

image_thumb11[1]

Now go the the Trigger tab; here is where the new Gated Check-in can be selected:

image_thumb31

Next go to the Workspace tab, and select the folder containing your solution (both the library and test projects).

image_thumb5

Next come Build Defaults, the usual (you might need to create a shared folder so you can map to it here; make sure the Build Service account can access it):

image_thumb7

I’ve left everything in the Process tab to its default value, but you might want to double check the Automated Tests. Team Build will run all tests in all assemblies whose name contains test.

image_thumb9

Also note the Fail Build On Test Failure setting; you can change it to true to ensure nobody can check-in with failing tests.

image_thumb11

If you’re using the Layer Diagram, you can also validate it during the build.

And finally Retention Policy, where you can choose whatever you like.

Close the window and save your changes.

You might want to test your build definition by queuing it. It should work:

image_thumb14

Ok, now let’s make a change to our code that would break the build by failing one on the tests:

   1: namespace Lib
   2: {
   3:   public class Code
   4:   {
   5:     public int Test(int i, int j)
   6:     {
   7:       return i - j;
   8:     }
   9:   }
  10: }

I’ve simply changed to + sign into a – sign.

Now open the Pending Changes window and click the Check In button. The Gated Check-in dialog should appear:

image_thumb16

Note the Shelveset and Build definition. If you have more than one build definition, things change, we’ll look at this later.

Also note the Preserve my pending changes locally. This works exactly the same way as normal shelving, so if you leave it checked, your changes are left on your machine. If the build fails, everything is the same. If you uncheck it, your changes will be shelved, but then you will have to make sure you reconcile back with the server’s version after the check in succeeds.

Ok, Click the Build Changes button. A build should start. Open the Build Explorer if it doesn’t do so automatically:

image_thumb18

The tests failed, so TFS decides that the check in failed:

image_thumb23

image_thumb25

Change the code back to use the + sign. Check In. This should now succeed.

image_thumb26

Now this really become interesting if two developers check-in conflicting changes. We can emulate this using two workspaces. So I’ve setup another workspace mapped to the same project. To do this, go to Source Control Explorer and open the Workspace: drop-down list:

image_thumb1

Select Workspaces…, this should open the Manage Workspaces dialog (you will have other names for any workspaces you might already have):

image_thumb3

Now pick a name, and in the Working Folders select your project mapping, one for the server, one for on your disk. For example:

image_thumb51

Then get all files locally (TFS will suggest this anyway). To switch between the workspaces you simply select it from the “Workspace:” dropdown list.

In one workspace rename the Test method in the Code class to Add. Use the Rename feature to ensure all references are renamed as well… Run all tests, they should succeed. Don’t check in yet.

Open your solution in the other workspace. Change the implementation of the Test method like this:

   1: public class Code
   2: {
   3:   public int Test(int i, int j)
   4:   {
   5:     if (j == 4) j = 8;
   6:     return i + j;
   7:   }
   8: }

And change the unit tests as well:

   1: [TestMethod()]
   2: public void Test2And4Returns10()
   3: {
   4:   Code target = new Code();
   5:   int i = 2; 
   6:   int j = 4; 
   7:   int expected = 10; 
   8:   int actual;
   9:   actual = target.Test(i, j);
  10:   Assert.AreEqual(expected, actual);
  11: }

Run all tests. They should succeed. Then check In. A build should start. While that is running check in your other changes (other workspace). Because your first check in is still running you shouldn’t see any conflict with your other changes. Actually, both builds should work, because the second build will merge the first build’s changes in the workspace, and they auto-Merge…

Let’s try to really break it now. In one workspace add another method to call the Add method (reconcile the workspace first, or do a recursive get-latest version):

   1: public class Code
   2: {
   3:   public int Add(int i, int j)
   4:   {
   5:     if (j == 4) j = 7;
   6:     return i + j;
   7:   }
   8:  
   9:   public void OtherMethod()
  10:   {
  11:     int x = Add(3, 2);
  12:   }
  13: }

Then in the other workspace rename the Add method again. Check this workspace in, then the other workspace. Because the extra method doesn’t get the Add method renamed, the build will break:

image_thumb71

Merge your code with the current check in code, and retry. This should now succeed.