During the past year, I've written in .NET UPDATE about details of some .NET Framework pieces—particularly Web services and the newest Universal Description, Discovery, and Integration (UDDI) specification. With the start of the new year, however, I'd like to step back and examine the greater picture of what the .NET Framework is all about.
As with other system architectures, you can represent .NET with a simple diagram showing how all the parts fall in relationship to one another. The lower a piece is on the diagram, the more fundamental that piece is to the functioning of all other pieces. In the .NET diagram, the foundation piece is the Common Language Runtime (CLR). The CLR is the piece that makes everything else in a .NET application work.
The CLR is fundamental to .NET's operation because .NET is supposed to be language-agnostic to at least some degree. But making a programming architecture language-agnostic is not a simple task. First, different languages have different ways of representing similar kinds of data—that is, they have different systems for representing types of data. For example, some languages see integers as a series of bits, whereas other languages see integers as objects, and yet other languages see integers as either bits or objects. Even applications or components written in the same language can encounter type system problems if the types aren't clearly defined in the language or an application is using user-defined types.
Second, type descriptions are usually stored in a separate source file, such as the header files that C++ uses. When a program is compiled, its metadata containing the type information might be lost, meaning that only languages that can read the source file can read the type information. (Type libraries, which COM uses, seek to resolve this problem.)
These two problems—different ways of defining types and difficulty in making type information available to different languages—can make creating components and applications that are truly language-independent—but that can still work together—difficult. As a simple example, consider how you can use a batch file to run a VBScript script, even though the batch file and the script don't report errors in the same way and don't refer to devices such as logical drives in the same way. And, batch files and scripts are very simple—and Microsoft-specific—ways of programming. The problems increase in scale with the complexity of the language.
The CLR consists of three main components of the .NET architecture that attempt to resolve these two problems. A type system supports the many types and operations of modern programming languages. A metadata system preserves metadata with types when programs are compiled. At runtime, other compilers can access this metadata. And the CLR's execution system runs the programs, referring to the metadata.
The catch to the CLR, of course, is that the languages developers use to build .NET applications have to work with it. A type not found in the CLR type system won't work. You might have heard that you can use multiple languages to develop applications on the .NET Framework, but that the application will work better if you use Microsoft languages. It's not that .NET works better with Microsoft languages per se, but that languages that use types found in the CLR will be able to use more of their capabilities. That's why you can use Visual Basic .NET to develop .NET applications, but you can't use Visual Basic (VB).
And there's the rub. Programming languages are designed to fulfill a particular need, so although programming languages might accomplish the same kinds of tasks, the specific way they conduct those tasks—and the specific tasks they're designed to perform—differ. That's why some languages are better than others for certain operations. A language-agnostic system permits more cross-platform and cross-language development but homogenizes all the functionality.