24. Managed Execution Environments
The comparison between [C#/IL Code/CLR] and [Java/Byte-Code/JVM] is an inevitable and valid comparison to make. I thought the best way to make sense of these comparisons was to explain why these technologies were made in the first place.
With C and C++ programs, you generally compile the source code to assembly language code which will only run on a particular processor and a particular OS. The compiler needs to know which processor it is targeting, because processors vary in their instruction sets. The compiler also needs to know what OS it is targeting, because OSs vary in ways such as how executables work and how they implement some basic C/C++ constructs such as allocating memory. This C/C++ model has been very successful (most software you're using probably has been compiled like this), but has its limitations:
- Does not provide a program with a very rich interface to interact with other programs (Microsoft's COM was built to address this limitation)
- Does not allow a program to be distributed in a form which can be used as is on different platforms
- Does not allow a program's execution to be limited to a sand box of safe operations
Java addressed these problems in the same way Smalltalk had done before it by having Java compile to byte-code which then runs on a virtual machine. Byte-code maintains the basic structure of a program before it is compiled, thus making it possible for a Java program to richly interact with another program. Byte-code is also machine-independent, which means the same class file can be used on a number of platforms. Finally, the fact that the Java language did not have explicit memory manipulation (via pointers) made it well suited to writing sand-boxed programs.
Originally virtual machines had an interpreter which converted a stream of byte-code instructions to machine code on the fly, but this dreadfully slow process was never appealing to the performance conscious programmer. Today most Java Virtual Machines use a Just-In-Time compiler which basically compiles to machine-code class skeletons just before they enter scope and method bodies just before they are executed. It is also possible to convert a Java program to assembly language before it runs to eliminate the overhead in start-up time and memory of a Just-In-Time compiler. As with compiling a Visual C++ program, this process does not necessarily remove the program's dependence on a runtime. The Java runtime (also covered by the term "Java Virtual Machine") will handle many vital parts of the programs execution such as garbage collection and security. This runtime is referred to as a managed execution environment.
Though somewhat obscured by terminology, the basic model .NET uses is the same as described above, though it was built to never use intepreting. Important improvements .NET will offer will come from the IL design itself, since the only way Java can match such improvements is by changing the byte-code specification which would generate serious compatibility issues. I don't want to discuss in detail these improvements - it should be left to those rare developers who understand both byte-code and IL-code. For the 99% of developers like myself who realistically aren't going to be studying the IL-Code specification, here are some of the design decisions for IL which are intended to improve upon byte-code:
- To provide greater type neutrality (helps implementing templates)
- To provide greater language neutrality
- To always be compiled to assembly language before executing, and never interpreted
- To allow additional declarative information to be added to classes, methods, etc., see 15. Attributes
Currently the CLR has yet to provide multi-OS support, but provides greater interoperability to JVMs in other areas (See 26. Interoperability)
A language is pretty much useless without libraries. C# has remarkably few core libraries, but utilizes the libraries of the .NET framework (some of which were built with C#). This article is mainly concerned with addressing the C# language in particular, rather than on .NET, which is best dealt with in a separate article. Briefly, the .NET libraries come with a rich set of libraries including Threading, Collection, XML, ADO+, ASP+, GDI+ & WinForms libraries. Some of these libraries are cross-platform, while others are Windows dependent, but see the next section for a discussion on platform support.