.Net is a maturing platform. The first .NET alphas and betas went to a selected group of people years and years ago. At this point, we are approaching the third major installment of Visual Studio .NET (now called "Visual Studio 2005"). Surely at this point, nobody has to explain what .NET and the Managed Platform is. Or do we?
I am always astonished at how difficult it can be for me to explain .NET. The whole "thing" is simply much too big to explain in a few sentences. There are many different technologies that all run under the .NET moniker. From a developer's point of view, .NET mainly means Visual Studio .NET. Generally, when I hear developers explain .NET, I hear, "Visual Studio .NET is the collection of programming languages, compilers, tools, the .NET Framework, and the CLR (Common Language Runtime)." Sounds easy enough, but (aside from the fact that this statement simply ignores .NET servers and other technologies Microsoft labeled as ".NET") is that sentence true, even for developer technologies?
In fact, the definition is actually incorrect! Visual Studio (.NET) is a tool that developers can use to write applications for the ".NET Managed Platform" or simply the "Managed Platform." The Common Language Runtime (CLR), the .NET Framework, and Visual Studio (.NET) are distinctly different components. For convenience and simplicity's sake, many developers simply ignore the difference between those parts, but at the same time, this simplification keeps developers from understanding core concepts of the Managed Platform, even years after its initial introduction. I think this is reason enough to investigate the situation a bit further.
A Brief History of Code Execution
So what exactly is the Managed Platform vs. Visual Studio? To understand the Managed Platform, I need to take you on a short excursion into the history of programming. In the early days of PC programming, compilers created code that was meant to be executed in a DOS environment, by creating code that can run natively on the processor. Generally, high level languages (like C) provided standard libraries that simplified the overall development process. In C (and C++) for instance, files such as "stdio.h" were included in projects to augment the sparse C programming language. Some languages - such as C++ - chose to compile secondary components into the main executable while others - such as Visual FoxPro - required these components to be available for runtime linking. Some languages even opted for so-called "runtime environments" that allowed a simplified compilation step, since the runtime was capable of executing the main application in a semi-interpreted mode.
Whether the code was compiled or interpreted, these approaches have two things in common:
1) All of these mechanisms were language specific. They really could not be used in any environment other than the language the mechanism was created for. The operating system has nothing to do with standard libraries or runtime environments. In fact, the operating system has no knowledge of standard libraries or runtime environments. All these mechanisms are simple language mechanics used to create individual languages that are as productive as possible.
2) No matter how many standard libraries and runtime layers are involved, each language compiler provides a chain of techniques and technologies that end up as "native code," code that can be directly executed by the processor. This provides the great advantage of raw speed since each language can utilize the processor to the best of its abilities. In fact, some vendors specialized in creating compilers that optimized for raw execution speed vs. functionality, offering huge advantages in the programming language market.
With the introduction of Windows, things changed a bit. Programming languages had to use the Windows API to create applications that looked like Windows. It was no longer possible to compile code with almost complete disregard to the operating system. Instead, languages made calls into the OS to create elements such as the user interface. In some languages, such as C++, developers were directly exposed to mechanisms such as launching windows. In other languages, such as Visual Basic or Visual FoxPro, a layer of abstraction allowed developers to focus on business problems rather than on creating windows, buttons, and text boxes. Under the hood however, the same calls were made into the operating system. This is a drastic difference to the old DOS days. In FoxPro for instance, the Windows and the DOS versions have identical commands to create a window. In DOS however, FoxPro has to provide its own window display and management mechanism, while FoxPro for Windows passed calls to draw screen elements to the Windows API.
From the compiler's point of view, the Windows environment is not that different from the DOS environment. Programming languages that target Windows use more standard components that are either compiled into an executable, or linked at runtime, but at their core, compilers create similar executable code that can be executed directly (natively) on the processor. Of course, Windows introduces many advances over the early DOS days such as OLE and COM, but those technologies are invoked at a relatively high level. It is also up to individual programming languages to support these technologies. For example, older versions of Visual Basic did not support COM. Simply compiling an EXE was not enough to support COM services, even though the OS provided COM support.
No matter how an application of the pre-.NET generation is compiled, at the end of the compilation chain, we always arrive at native code, either by compiling native code directly or by providing a small, individual runtime environment that fills the gaps between the intermediate version and machine language. Either way, we get native code that simply takes advantages of the processor's capabilities.
In the .NET generation of programming languages, this paradigm has changed! But why? What is wrong with compiling native machine code?
The Problem with Native Code
Native code has a number of intrinsic problems. Of course, machine code that takes full advantage of the processor provides great performance. However, there is no control over the code that is executed. The processor simply takes the stream of 0s and 1s and runs it. While this is fast, the problem is that in today's world, one can not be quite sure where that code came from, and what it does. The processor itself does not provide any mechanisms to apply rules to code execution. For instance, it is not possible to define that code loaded from the local network needs to adhere to different execution rules than code loaded from the local hard drive or from the Internet. Similarly, it is not possible to configure a processor according to an individual user or system administrator's desires. It simply is not possible to provide a truly secure environment with native code.
Furthermore, the processor can not be feature-enhanced through software. Mechanisms such as COM have to be implemented and supported individually by all programming languages. Whenever a new technology (such as object pooling as it is provided by COM+) is introduced, only languages that specifically support that technology can take advantage of it. It is not possible to add object pooling to the processor in a way that would allow all EXEs to take advantage of the feature, independent of whether or not the language that created the EXE knows about COM+.
Another problem with native code is that problems with the code can not be handled in a generic way. A typical example for this is the buffer overrun situation. While the cause of this vulnerability is well known, fixing it is a serious problem as each developer has to understand the problem and fix each application and every single line of code individually. The only generic fix to this sort of problem is to augment a processor's architecture and provide a hardware fix. Such a fix is hard to deploy (since only newer processors can have a fix for such problems) and therefore results in sub-satisfactory distribution. Also, this approach is only feasible for extremely severe and exceptional cases.
The Managed Platform to the Rescue
For the first time in code execution history, the Managed Platform steers clear of native code. Compilers that target the managed platform do not worry about creating machine code. Instead, managed platform compilers create so-called "Intermediate Language" or "IL". This code is then executed by the "Common Language Runtime" (a.k.a CLR) or in general, by the "Managed Platform." In .NET, this is done by a Just-In-Time (JIT) compiler, which takes IL and compiles it into executable code in a very controlled way. During and before this step, the managed platform can apply rules and even create different code based on a number of parameters. The JIT compilation step is an implementation detail developers should not worry about. In fact, managed code execution could happen quite differently. It is not out of the question that someone develops a "hardware accelerator for IL" that completely eliminates the need for JIT compilation. Also, it is conceivable that IL will run on a wide variety of platforms. In fact, today .NET runs on handheld devices, telephones, end even SPOT ("Small Personal Object Technology") devices, such as the Smart Watches from MSN Direct.
The key difference, however, is that as IL is executed, it happens in a controlled fashion. The Managed Platform inspects code and can apply rules. Using this technology, it is possible to define rules that allow code loaded over the Internet to run under a different set of rules than code loaded locally. By default, the .NET Managed Platform already provides a sensible set of rules, but of course, system administrators (and users with appropriate rights in general) can modify these rules if they need to.
The Managed Platform also goes beyond plain code execution and includes another controlled environment: Memory management. Rather than allocating and freeing memory directly, the managed platform provides a memory management mechanism. This prevents memory leaks as well as problems such as buffer overruns.
What About Visual Studio and the .NET Framework?
The .NET Framework is a set of language-neutral classes that is compiled into IL and targets the Managed Platform. The .NET Framework completely depends on the Managed Platform and would be useless without it. The opposite, however, is not true. If Microsoft one day decided to completely replace the .NET Framework with a different library, this decision would not at all influence the CLR. Think of the CLR/Managed Platform as a successor to the I86 processor architecture: software that replaces the processor (at least conceptually). The .NET Framework is, of course, infinitely useful, but it clearly has to be seen as a separate technology from the CLR. A fact that is often misunderstood.
Visual Studio (.NET or 2005) is one step further removed from the CLR. It is simply a tool that creates applications compiled for the Managed Platform, using the .NET Framework. Visual Studio is not the only tool that does this. Many tools are available for the same purpose including command line compilers to free tools such as Web Matrix. Advanced development environments such as Borland's Delphi Builder and C# Builder now target the Managed Platform. Therefore, seeing Visual Studio .NET as "just another version of Visual Basic" is somewhat misleading and does not accurately reflect the size of the leap Microsoft has made. The paradigm shift is unprecedented in the history of programming languages and environments.
What's Next?
I expect practically all language vendors to provide managed versions of their languages, similar to what we saw when programming languages transitioned into the Windows world. Furthermore, I expect to see the Managed Platform on more and more non-PC devices. This process is already well under way.
What's more interesting are developments in "Longhorn" (the next version of Windows). Currently, the Managed Platform runs on Windows. In Longhorn, the CLR is not a component that gets installed in addition to the operating system. In the future, it will probably be more accurate to say, "Windows runs on the Managed Platform." (This puts an interesting spin on the question of whether or not the Managed Platform will be converted to Linux. The more proper question will probably be "will someone write a version of Linux on the Managed Platform?") Don't underestimate the importance of being able to target this platform and create code that runs "managed" because only managed code shall then be considered "native." Old-style machine code will certainly keep running for a long time to come, but this will probably be in a compatibility mode. Also, I expect that system administrators will grow frustrated with this "legacy" code that can not be managed the same way more modern applications are. Five or ten years from now, how many such "legacy flies" will be in your ointment?