Sunday, 25 October 2009

Dynamic Binding in .NET

What is the root of all evil in COM? Yes, I know this blog is about .NET, but this is relevant, so bear with me.

So what is the root of all evil in COM? The COM veterans will reply instantly: it is late binding. Why is that so? Well, the whole point about COM is interface programming. That is, a server says exactly what it can do which means that a client can be written to use that functionality reassured that it knows that the functionality will be present. Interface programming defines a contract, the server must abide by this contract and the client is reassured that the contract is followed to the letter. The really neat thing about this contract is that the client and server can be in different processes or on different machines and yet the client will still be able to call the server. This form of interface programming is called early binding. The compiler has information about the interface (usually in header files) and refuses to compile the code if the client attempts to call a method not present on the interface, or calls a method with the wrong number or wrong type of parameters.

The compiler. A wonderful piece of software. Not only does it do the translation from your high level language into something the computer can execute, but it also makes sure that what you have written is correct and it will minimise the errors that could occur at runtime. This improves your reputation as a developer, it reduces the time taken to test and debug code, and it makes your code more robust. All these benefits make your project manager and your customer happy. Wonderful!

But does this apply unnecessary restrictions on the developer? Not at all. If a COM developer decides that the next version of the object needs more functionality then COM provides a solution: add a new interface with the new functionality. There is one rule that no COM developer should ever break, and that is once an interface is published it never changes. This immutable aspect of interfaces is vital for COM.

However, the problem with interface programming was that some languages (dare I mention a language that has the word Basic in its name?) were not fully functional when it comes to COM. Further, interface programming requires discipline from the developer and some languages naturally attract the less disciplined developers. (Don't tell me that such developers are free-spirited, they are simply sloppy.) So to accommodate such languages and developers Microsoft relaxed the rules and created late binding. With late binding the developer writes code how they think the object should work. Such compilers have had their wings clipped and so only do basic checking (if I was such a compiler I would sulk in the corner at this point). Don't misunderstand me, the code may well work in practice, but no one knows for sure until the code is actually run.

As a professional developer I strive to write good quality code that fits the customer's spec as close as possible. To do this I have to test and debug the code extensively. That is my job. The compiler helps here because it performs checks on the code for possible issues, including type checks. When you use late binding the compiler performs fewer checks: it essentially ignores the types used through late binding. This means that there is a good possibility that there will be an error in the late binding code. So who experiences such errors? The answer is whoever it is that is running the code. If the developer is thorough then they will test, test, test, so that every possible runtime error is experienced. But can you, as the customer, be sure that the developer is thorough? The reason why I dislike late binding is that it raises the possibility - unacceptably, in my view - of the customer experiencing a runtime error. As a professional developer you should not be using your customers to test your code, but that is what happens when you use late binding.

The language war between C++ and VB3 had a skirmish over late binding. Generally, C++ developers preferred not to touch late binding and VB3 developers had no choice, they had to
, so they grew to love it (later versions of VB introduced early binding, but bad habits take a long time to die). C++ developers could write late binding COM code but it was tedious since it involved type library queries and IDispatch calls. OLE Automation is the main reason for late binding and the most prolific user of OLE Automation is Microsoft Office. The widespread use Office means that there is a demand for C++ developers to write late binding code and so eventually the Visual C++ libraries provided mechanisms to make early binding code easier to write (COleDispatchDriver, #import).

Let's return back to .NET. Type safety is very important from a security point of view, and .NET takes security seriously (well, we shall see whether this statement still applies to .NET 4, but that is an interesting post for the future). If the runtime detects that code calls a member on the object not present in its type information, or if the member does exist but the call uses the wrong number of parameters or the wrong parameter types, then the runtime throws an exception. As a developer you have to make sure that the customer never sees such exceptions, and it is better to write your code to be type safe than to catch type mismatch exceptions. The compiler works to help you write type safe code. If you really want to use late binding in .NET you can always use Reflection. With Reflection you can write code that checks the functionality of a class and set up the managed stack with the appropriate parameters. Calling code this way is tedious and it puts off a lot of developers. Good thing too. Type safety is vitally important, so every effort should be made to dissuade people from writing type unsafe code. But you can see that there is a parallel with C++ and type libraries: it is possible for .NET developers to write late binding code but since it takes a lot of work developers were dissuaded from doing something that had the potential of introducing difficult to detect runtime exceptions. Until now.

Now for the subject of this post. C# 4 will have a new keyword called dynamic. This brings late binding to C#. I'll repeat that: the dynamic keyword means that our nice type safe language, C#, has been VB3-ified. With this new keyword the developer can write code to call any method in any way they choose and the compiler will perform no type safety checks. Consequently, all type safety checks are left to the CLR runtime (which has magically been renamed DLR Dynamic Language Runtime), when running on the customer's machine, at which point it is too late for the developer to fix the code. This is exactly the case with late binding (OLE automation) in VB3, and will happen far to frequently soon with C#.

Do I sound disheartened? Yes, and the reason is that I am a COM consultant as well as a .NET consultant and I often in the past I was hired by companies to fix the problems they had with COM code. In almost all cases the reason for the issues was that the developers did not follow interface programming rules. Usually I was asked to fix code that was written in Visual Basic or written for Visual Basic, and I can ascribe a lot of the problems coming from developers with a late binding mindset writing interface code. The two do not mix. Interface programming is precise, late binding is sloppy. Yet now our beloved C# has been polluted with the a keyword that allows C# developers to write sloppy code.

Actually, it is not the keyword that I object to, it is the fact that the keyword is allowed by default. The C# compiler does not allow you to write .NET unsafe code unless you compile your assembly with the /unsafe switch. The same should be true with dynamic. If the developer has to use the /unsafe switch then he gets an immediate indication that the code he is writing is not as type safe as the code that C# usually generates. I hope that Microsoft makes this change to the compiler.

So how does this rather evil keyword work? Let's look at an example.
class Item
{
int t;
public int Tail { get { return t; } }
public Item(int i) { t = i; }
}

Item i = new Item(10);
Console.WriteLine(i.Tail);
object o = new Item(10);
Console.WriteLine(o.Tail); // Compiler error CS1061

In this code we create an object of type Item and initialise it with a value of 20. Then we print out the the value of the Tail property. The first pair of lines access the Item object through a typed variable, and so the compiler is happy with the line that accesses the Tail property. In the second pair the Item object is accessed through an object variable. The compiler enforces type safety and only allows the code to access Object members and since there is no Tail property on the Object class the compiler generates error CS1061. The solution, of course, is to cast the variable to the appropriate type:
Console.WriteLine((o as Item).Tail);

This code has its inherent dangers. The variable o may not be an object of type Item and hence the casting (in this case using the as operator) will fail at runtime. .NET developers know this and the better developers take steps to avoid writing untyped code like this. (This is one reason for generic code: it eliminates many of the reasons for writing untyped code). Now consider the following code:
Console.WriteLine((o as Item).Tai1);

This will generate an error of CS1061. Why? Well the reason is that I typed a number 1 instead of the lower case letter L in the name of the property Tail. The compiler warns me that my sloppy typing has genrated an error in the code. The compiler, of course, sees the character 0x31 rather than the character 0x6c, whereas my 46 year-old eyes can easily mistake a 1 for an l. It's a good thing that I have the C# compiler to help me, isn't it?

Now let's see how the dynamic keyword is used. The first point to make is that it should be treated a bit like the object keyword in that it can be assigned to any type:
dynamic d = new Item(10);
Console.WriteLine(d.Tail);

However, the interesting thing is that there is no type checking performed on the variable by the compiler. The code above causes dynamic checking at runtime that the variable d has a property called Tail, and in this case the code will compile and run with no errors. However, in the following code, I have mistyped a 1 for an l again (must get some new glasses...):
Console.WriteLine(d.Tai1);

This compiles fine because there are no compile time checks, but at runtime I get an exception:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
was unhandled 'Dynamic.Item' does not contain
a definition for 'Tai1'

As a user of this code I have to contact the developer and tell him that he needs to get his eyes tested: the user is debugging the code.

So what is happening under the covers? Well, as you can imagine there is some reflection going on. The key to this code is a class called Binder in the Microsoft.CSharp.RuntimeBinder namespace. The compiler generates code to call methods on this class to invoke members of the dynamic object, and the Binder class returns (effectively) a delegate to the member. For example, to call the Tail property the compiler generates the following code:
CSharpArgumentInfo[] info = new CSharpArgumentInfo[] {
CSharpArgumentInfo.Create(
CSharpArgumentInfoFlags.None, null) };
CallSite<Func<CallSite, object, object>>
pTail =
CallSite<Func<CallSite, object, object>>
.Create(
Binder.GetMember(
CSharpBinderFlags.None, "Tail",
typeof(Program), info));

The Tail property is effectively a method called get_Tail that has no parameters and returns an integer, so the info array with the information about the parameters passed to the method has one entry that has null values (interestingly, you cannot pass null for this parameter, neither can you pass an array with zero members, you have to create one member that has these "null" values).

The Func<> delegate has three parameters, the first is the CallSite object that defines where the code is being executed (in this case the code is executing in a method of the Program class, see the third parameter of the GetMember method); the second parameter is used to supply the object to be called (Tail is an instance member) and the last parameter is the return type. Huh? The return type is object? It appears so. The CallSite object will only return an object and it is up to you to cast it.
object o = new Item(20);
int ret = (int)pTail.Target.Invoke(pTail, o);

I am not sure why you cannot give a return type other than object (and provide the type as a parameter when creating the CallSite). However, the Binder class does have a method to perform the casting for you:
CallSite<Func<CallSite, object, int>>
pConvert =
CallSite<Func<CallSite, object, int>>.Create(
Binder.Convert(
CSharpBinderFlags.None, typeof(int)));

CSharpArgumentInfo[] info = new CSharpArgumentInfo[] {
CSharpArgumentInfo.Create(
CSharpArgumentInfoFlags.None, null) };
CallSite<Func<CallSite, object, object>>
pTail =
CallSite<Func<CallSite, object, object>>.Create(
Binder.GetMember(
CSharpBinderFlags.None, "Tail",
typeof(Program), info));

object o = new Item(20);
int ret = pConvert.Target.Invoke(
pConvert, pTail.Target.Invoke(pTail, o));
Console.WriteLine(ret);

This code is rather complicated, but in effect it is the code for the following C#
dynamic o = new Item(20);
Console.WriteLine((int)o.Tail);

The Binder/CallSite code is reminiscent of the sort of code that the MFC Automation wizard or the #import directive creates. The code is generic and cumbersome and should be avoided when possible. No doubt by now you have seen several blogs saying "Wow, ain't this cool?" trying to persuade you that you can relax your C# code into sloppy VB3 code. Resist the urge.

But there must be a reason for dynamic. There is: calling OLE Automation code. In this case the keyword dramatically reduces the amount of code you have to write, and so I am happy for it to be used. I am just wary that the keyword can be used inappropriately. Hence we come full circle. My advice to you as a developer is to only ever use dynamic when you write OLE Automation COM interop code and you should take every step possible to avoid it at all other times. My plea to Microsoft is to change the C# compiler so that it only allows the use of dynamic when the /unsafe (or equivalent) switch is used. If Microsoft does not do this, then I expect in a year's time to be asked to fix other people's code and find that a large proportion comes from developers using the "cool" dynamic keyword inappropriately.

Saturday, 24 October 2009

Fixing the "application cannot start" issue

In my last blog post I described how dragging around the docked tool windows causes some type of corruption that means that Visual Studio 2010 will not load giving an error of "The application cannot start". I played around a bit with this until I decided that it must be some user data issue and hence I decided to reset all the settings that I had made in the brief time I had used VS2010. The way to do this is to use the /resetuserdata command line switch:
  1. Click Start Menu
  2. Click All Programs, Visual Studio 2010, Visual Studio Tools
  3. Click Visual Studio Command Prompt (2010) shortcut
  4. At the command prompt type devenv /resetuserdata
  5. Nothing appear to happen for a few seconds, and then the command prompt appears indicating that the process has completed.
Now when you start Visual Studio 2010 you will no longer get the error dialog, but you will have to set all the options that you may have set before. After finding a workaround I went to the connect website to bug the issue and found that it had already been reported: Visual Studio 2010 Beta 2 crashes with "The application cannot start." dialog (WinDbg output attached).

Visual Studio 2010 Beta 2

Visual Studio 2010 beta 2 was released to the web on the 21 October. You can download it from here. Since I no longer get invites to Microsoft betas (they really don't like what I say about their products), I am approaching this release like the average punter: download the public beta, work through the tutorials and then decide if the product should be given disk space. As a side effect of this, you'll not find me spinning the Microsoft line.

I opted to download the ISO of the installation DVD. This was a simple process: download four files (three rar archive and an exe) then run the exe. This process decompresses the archives and stitches them together as a single DVD ISO image. In my case Vista told me that there was a problem with the "installation" (ie decompression) so I deleted the ISO file and repeated the process. When I got the error a second time I ignored it.

I decided that I would not install this beta on the same machine that I use for my work, instead I created a Virtual PC and installed it there. Microsoft recommends 1Gb of memory but since I only have 2Gb on my development machine I decided to create the VPC with 660Mb (later, I found that this was not an issue). I have a clean VPC with XP Service Pack 3 installed, so I copied the virtual hard disk (vhd) for this and renamed the copy. I then used this for the disk of my new VPC. This saved me the effort of installing an operating system. The next action to do was to boot the VPC and in Microsoft Virtual PC use the Capture ISO Image menu item to point to the VS2010 ISO file. XP autostart then started the installation from the ISO image. The installation took about 20 minutes with no issues.

The VS2010 installation includes .NET Framework 4.0 beta 2, Silverlight 3 SDK, Synchronization Services and SQL Server Express 2008. Afterwards there was an option to install help locally which I accepted and the install program clunked away for another 10 minutes, copying something.

After the installation completed I started help for VS through the Start Menu. I waited for MSDN library to start up, but instead, an icon appeared in the notification area (right). Then Internet Explorer appeared showing the first page of the documentation. Clearly the install program copied the HTML files (or a compressed version) to my hard disk and then installed a minimal HTTP Server to serve these documentation pages. The last few versions of MSDN library have hogged memory and took an age to close down (often throwing an exception in the process, as if the application just refuses to go away), so something had to be done about it. I am not sure if doing it this way is a good idea, but no doubt as I use it I will be able to make up my mind. (Two things immediately come to mind: contents and search. I find the tree control on the MSDN web page irritating to use, so I hope this was not used in the new VS help. Microsoft have never been able to provide a web search engine that got anywhere near as powerful as Google, so I hope searching the locally installed help uses a better search engine than Microsoft usually provides.)

I then started VS2010 through the Start Menu. The first thing to say is that Microsoft have rebranded the Visual Studio colours. Previous versions have used a reddish orangey theme, now Microsoft have decided to use a steel blue grey theme. It looks nice, but clashes with the bright blue standard theme of XP. Microsoft have also decided to replace the light grey background (when you have an empty environment) used in all the versions of VS I can remember, with a dark grey background. This looks fine, and I found no issues with accessibility.

The docked tool windows behave as they do in VS2008, and I dragged Solution Explorer off the edge of the environment to undock it, and see if I could dock it elsewhere. The tool window disappeared. No bother, I thought, and tried to show it again with the View menu item. Nothing happened. Then I shut down VS2010 and restarted it to see if I could reset the program. I then got the error box, below, saying that VS2010 cannot start:

Needless to say, this is not a good start. First, I need to bug this (and hope that Microsoft do not give their stock replies of "by design" or "will be fixed in the next version") and then I will try to find a workaround to get VS to start (I suspect I may need to repair it). When I have done that I will report back here my impression of what is new in VS2010. However before I sign off I have to stress:

If you are using Visual Studio 2010 beta 2 do not move the docked windows because afterwards VS2010 will refuse to start.