In this article, I will propose why developers like yourself should care about .NET, even if you are not planning to move to .NET. There certainly is a lot of marketing goo oozing around about .NET, but let's skip the goo and talk about the technical aspects. Specifically, I will discuss why .NET is important to developers.
Like it or not, .NET is coming
.NET is the future of development not only for the Windows platform, but other operating systems as well. If you are not moving to .NET now, you should at least be keeping up to date with it and reevaluating it at regular intervals to determine when you will begin moving to it.
.NET is coming. Ignoring this fact will not slow it, or stop it. Those that do not move to it will be dinosaurs. It's better to plan for a migration than to become extinct.
If you begin evaluating .NET now and plan for a smooth and timely migration, you will reap the benefits. However, if you wait too long, the future is quite predictable, and can easily be seen by looking at the DOS developer that we all know who refuses to admit Windows has arrived.
Why not Java?
This article is not a tirade or attack on Java. In general, this article is targeted at Win32 developers and not Java developers. But the question still arises, “Why .NET instead of Java?”. I will only summarize my view on this in this article. In another future article, I shall compare .NET and Java and prognosticate on the future.
Java is an established platform with its own merits. This article merely states my reasons why I think .NET is important. I have only referenced the Java platform when a contrast or specific difference existed that I felt was of particular importance.
.NET is superior to Java as a platform in many areas, while Java is superior in others. The key difference though is that .NET will close the gap in the future with little need for change, while Java cannot close the gaps without a major redesign into something quite different than it is now.
Some advantages that .NET has over Java are:
- Java is not just a platform, but a language. .NET is language independent. Adopting .NET does not force you to adopt a single, or even specific language. .NET can even support the Java language, and J# is very close to Java.
- Language interoperability.
- .NET can coexist with and even integrate with existing Win32 code.
- Moving to Java from Win32 is a complete paradigm shift. Moving to .NET is a more natural path for Win32 developers.
Reasons for .NET
"It's big, and it's Microsoft.". If I had a Euro for every time I heard that.... While this may be true, it's not a valid reason to move to .NET. You can paint the word Microsoft on a big jet. That does not mean people will eagerly sign up for a flight. In fact, you should be skeptical about .NET, but let's examine some tangible reasons why .NET is important to you.
Though while not a technical reason, this is still a reason to learn .NET. Microsoft is spending a lot of money on marketing .NET, and wooing companies to move to it. Many managers responsible for such decisions are not very technical, but do trust Microsoft. They will move to .NET purely on the basis that Microsoft tells them it is the only future, and when they see their competitors move to .NET.
When companies move, they of course need developers. Learning .NET now assures your future as an employable developer, and gives you a head start and more experience than other developers who wait to learn it at the last minute.
Unless you have been developing in a cave, you have most likely heard the term "Safe Code". But what exactly does this mean? Instead of safe code though, lets talk about "Pure Code".
Applications can be compiled and executed on the .NET platform, yet still be not "pure" .NET applications. "Pure" is a subjective term, and not necessarily an official one. I will define a pure .NET application as having the following attributes:
- 100% Safe Code
- 100% Managed Code
- P/Invoke Free
The ultimate goal of any .NET application is to use 100 % pure code and isolate all other code into separate assemblies. In a 100% .NET world all applications will run only pure code. Only device drivers, encryption, compression, and other such items shall run as unsafe code.
Managed code is code that is executed under the control of the .NET framework. Code that can be managed by the .NET framework is IL, or Intermediate Language based code. Unmanaged code contains CPU specific instructions produced by assembly language mnemonics, or a traditional compiler such as C++, or Delphi (.NET versions).
Languages such as C# and Visual Basic.NET produce only managed code. However Delphi, and especially C++ can produce mixed applications which contain both managed and unmanaged code.
Mixed mode applications can integrate with the .NET framework and allow easier phased migration from Win32. Mixed mode assemblies are also necessary for integrating with hardware. However, since a mixed mode application contains CPU and operating system specific information, this ties the .NET application to a specific CPU and operating system. Such applications therefore use .NET, but are do not run completely under the .NET framework and are not compatible with other .NET implementations such as Mono, the 64 bit .NET framework, and other future implementations.
Many server environments have security restrictions that only permit applications to be run if they are pure managed code. Unmanaged code items must be explicitly trusted by the administrator and are reserved for device drivers and the like.
In short, if any part of an application is unmanaged, the whole application should be considered unmanaged. If certain items such as hardware must be integrated with a managed wrapper is created. All such items should be created and deployed as separate isolated assemblies for easier management.
Safe code is code that strictly follows the rules of type safety of the .NET framework. Unsafe code is old code that does not follow such rules. Unsafe code permits use of pointers, machine specific byte orders, and language specific types. Unsafe code requires additional permissions to execute.
Assemblies can be checked with a tool called PEVerify to determine if it contains unsafe code. PEVerify is part of the .NET framework SDK.
P/Invoke is an abbreviation for Platform Invoke and refers to the ability to make calls directly to the operating system without using the .NET FCL. In Windows, P/Invoke also allows calls to be made to user or vendor DLL's. P/Invoke is similar to JNI in Java.
Using P/Invoke does not make code unsafe or unmanaged. It does however cause the application to rely on items specific to the operating system. This again makes the application unable to run on Mono, and other future implementations. P/Invoke should be avoided and functions in the FCL should be used instead when possible.
Because IL is generic, it is not tied to any particular CPU or hardware platform. While IL is currently only supported on Windows, its design is specifically built with other platforms in mind. On Linux, there is already a project called Mono to allow IL code to run on Linux. In the future, other platforms will implement IL execution as well.
.NET is language neutral. The three most common languages in .NET are C#, Visual Basic, and Delphi. But many others exist for .NET as well, including Fortran, Smalltalk, and others.
But .NET is more than just language neutral. .NET brings all the languages together through its CLR (Common Language Runtime) and CTS (Common Type System). The CLR and CTS allow all the languages to use assemblies produced by other languages as if they were produced by the same language. There is no more awkward translation of parameter types, calling conventions, or naming conventions. Now, C# users can use all code produced by Delphi programmers, Visual Basic users can use all code produced by C# developers, and any combination of languages. No longer are developers segregated by language and forced to interact only through difficult and awkward exports.
Imagine, if all of the sudden the universal translator from Star Trek were made available today enabling Russians to speak directly to Germans, to Dutch, to Spanish, to any language. Each using their own native tongue, yet each hearing in their own native tongue. That is exactly what .NET does for programming languages.
The Future is Faster
Does this mean .NET is slow now and you should suffer until we have even faster CPUs? No!
Let's take a step back and look at how we build applications today. When we compile our source code, the compiler emits assembly code for a specific type of CPU. For Win32, this might be for a 486 CPU. On a 486, the code runs a full potential. However, very few people today are running with 486 computers, and in fact, are using CPUs many versions newer. But since you cannot predict what your users will use, you must compile for the lowest possible factor. This also severely restricts Intel, AMD, and other CPU manufacturers, as backwards compatibility must be maintained for many generations.
With .NET code, your source code is compiled into IL. This IL is then executed on any CPU or operating system with the .NET framework. This IL is not just interpreted though, it is essentially compiled on demand using instruction sets optimized for the platform. This on-demand compiler can be easily updated in the future to support newer CPUs and even incompatible instruction sets. Each individual user then will run their own optimized version of your software, for their hardware. All without needing to ever recompile your code or redistribute your application to users.
Moving from the 16 bit world to the 32 bit world was quite painful for developers. It was not just a simple recompile of the code as many underlying support architectures changed. But with .NET, you can move into the 64 bit world and take advantage of the faster processing power without recompiling, redesigning, or even redistributing your software. That is what I call upgrade insurance!
While C++ can be compiled for many platforms, this requires each build to be built for each and every platform. This is a very maintenance intensive task, and expensive in many cases as well. Cross platform C++ code has a lot more restrictions, and often code does not compile well across platforms, while .NET code is always cross platform. The key factor though is that, in C++, for future platforms, you must recompile as compilers become available, while .NET code needs no changes or recompilation.
.NET 1.1 applications built with Visual Studio 2003 may not automatically take advantage of 64 bit CPUs. Because many developers are still writing unsafe code and relying on CPU word sizes, Visual Studio currently marks its IL output with a 32 bit flag. This will cause 64 bit .NET to execute these assemblies in 32 bit compatibility mode. This will take advantage of some of the 64 bit CPU, but not all.
If your code is safe and free of “bitness”, you can override this flag and your assembly should then run in 64 bit mode. The next version of Visual Studio which supports .NET 2.0 is planned to emit a platform neutral flag. Other .NET 1.1 languages may not have the conservative value that Visual Studio uses, and thus can take advantage of 64 bit with no changes.
While this limitation certainly is not pleasing, it is not a limitation of the .NET framework, but instead a design choice of Visual Studio.
Visual Basic over the years has had several "bad" features added to it which allowed and even encouraged bad programming practices. This has given Visual Basic a bad name in many circles.
.NET has forced VB back into the realm of proper development practices and will keep its designers from reverting it. This article is not a tirade on VB either, but for those of you who need a reminder, I have 2 words for you:
Option Implicit. This option is bad enough, but it's the default for projects. VB has many other such faults that .NET has forced to be fixed. VB.NET still has this option for backwards compatibility, but the default has been changed. Many other items have been eliminated completely.
I realize that this next topic will put me into hot water with C++ developers. But ..... C++ is a fantastic low level language - and that is exactly what it is designed for. But C++ because it is so suited to such, is not as well suited as an application language. Its insistent use of pointers for the simplest of tasks inherently makes it "unsafe" by the .NET definition.
Thus, we have C#. C# is a .NET conforming language based on C++. C# finally forces C++ programmers to give up old habits and move to safe programming practices.
Where does this leave C++? C++ is still the language of choice for writing unmanaged assemblies for direct hardware access, high performance number crunching, compression, and encryption. So, C++ stalwarts need not worry – C++ will be around for the foreseeable future. But your ranks will shrink as many of your fellow developers move partly or completely to C#.
For application, server, business, and general development, C++ developers should look to C#. While you lose many of the low level items you have grown to love in C++, C# is a language with a syntax based on C++, but built for .NET. It will irritate you at first, but you will grow to love it and you will not look back.
Pointers are fondly admired by C++ developers, but so were line numbers by Basic programmers. I certainly do not mean to compare modern C++ developers to Basic programmers, but the fundamental shift is the same. Once you move, you will not miss what you have lost and will be better off for it.
Code that runs on a .NET platform is less likely to crash, and it is virtually impossible for managed code to take down the system or affect other applications.
This is due to two factors:
- .NET restricts what applications can do, what they can access, and how they manage memory.
- .NET forces developers to use modern languages with modern programming practices. .NET forces developers to abandon old habits and techniques designed for computer systems of the 1970's era.
C++ developers are also quick to reply that “Modern C++ has warnings for X and Y, or compiler option Z can prevent that.”. The problem with warnings is that C++ issues so many warnings, and C++ developers often want to override them anyways that on each compile, a C++ program issues hundreds if not thousands of such warnings. Finding the important ones is not a quick or easy task. Compiler options are problematic too. Since C++ developers are typically speed freaks, nearly all such safeguards are turned off in releases, no matter if the code runs sufficiently fast or not. Since release code is used by a much larger user audience, the releases encounter situations never encountered in the debug releases and simply crash. .NET forces these checks to always be on, providing for better applications by properly handling exceptions instead of merely corrupting memory or other.
.NET has invoked fear in the minds of many developers. Some of the fears are based on facts but surrounded by misunderstandings, while others are based on pure misinformation, and in some cases, even religious beliefs. Let's examine a few of the more common ones with a logical approach.
- .NET has a Big Runtime.
.NET has a 20 megabyte runtime. That's too big for a normal application.
First of all it is not a run time library. The .NET framework is a complete platform similar to how Win32, DOS, Unix, and Java are platforms. Currently, .NET runs on top of Windows and thus must be installed.
The install for the 1.1 version of the .NET framework is approximately 20 megabytes. However, the Windows XP Service Pack 1 CDs include this runtime as part of their installation, and many users already have the framework installed. In the future, the .NET framework will gain wider and wider acceptance just as other Microsoft components have such as DirectX, etc. Most games rely on DirectX installation and install it without trouble or complaints of a run time.
Future versions of the Windows operating system will ship with the .NET framework installed as part of the native operating system.
20 megabytes is also not a very large distribution in the scheme of things. Most software are several megabytes or even larger. The .NET runtime only needs to be installed by those users who do not already have it, and thus is optional. Adding a 20 megabyte install to a CD distribution and installing if needed will not negatively impact deployment.
20 megabytes is more measurable in the world of electronic downloads. However, electronic downloads over the Internet are normally performed by technical savvy users who likely already have the framework installed, or have a DSL or better Internet connection.
The 20 megabytes also refers to the complete framework. When your application loads, it will not link to a 20 megabyte runtime that loads into memory, just as a standard Win32 application today does not load 200 megabytes of Windows support for each run.
- .NET is Slow.
Some .NET applications do in fact run slower. Compression and encryption routines are one example that often run slower. Such functions should be written using unmanaged code anyways because of the security implications and need to directly manipulate structures in specific ways that encryption requires.
However, such applications occupy a very small minority of the average development need. Most developers are developing either server side objects, or desktop applications. Such tasks when written properly will execute just as fast in Win32, or faster.
Faster? Yes faster. This is because the .NET framework implements and provides so many more services than what a Win32 application has available to it, and also because of how IL code is actually optimized and executed.
But I ported my application and it's 100 times slower!
That's a very common scenario. Many applications when ported do run 100 times or more slower than the original Win32 application. But I said they should run faster, right? So, how is this that so many applications run slower after porting?
The answer is simple - the applications were ported, but the design remained the same. That is, a straight port was performed without using the new techniques in development.
It's certainly possible to take a large engine from a 1960's hot rod and put it into a modern car and make it run. However, powering it on unleaded fuel, and integrating it in with the car system and bodies designed 40 years later will not yield the expected results. When porting to .NET, you need to take into account that it works differently in several key areas.
Do you have to redesign your application from the ground up? No. But you should look at some key areas and consider altering them to operate under the new paradigms so that they will run properly, and efficiently.
- Loss of Control.
Many developers have become very accustomed to having full control. This habit is especially true for C++ developers. Developing for .NET control is diminished if your definition of control is direct access to memory. In most object oriented languages, developers have been moving more and more away from direct memory access, and towards managed memory and object interfaces. .NET takes this to the next level and only allows managed memory and objects.
While at first, this may grate developers because they may need to change long established habits, the change is a good and even necessary one.
The Future of .NET
.NET is new. The current version of the framework is 1.1, with 2.0 in development and on the horizon likely in 2005. Because .NET is new, I will spend some time discussing the future of .NET which will help to explain why .NET is so important.
Even if you do not plan to move to .NET now, you will in the future. Developers and companies who resist the move to .NET in the future will be like developers writing Windows 3.1 or DOS applications today. .NET is coming - while you may not move to it now, the sooner you come to terms with the fact that you will move someday, the better.
Mono is a .NET implementation for Linux that allows managed .NET code to execute on Linux. Mono is exciting because it demonstrates that while Microsoft is the motivating force behind .NET, .NET itself can and will be available on other operating systems.
In the future, I expect that the .NET framework will be available on mainframe class computers. For enterprises with big investment in mainframes, this will be a big step. As demonstrated with Mono, this is something that is certainly possible, and is just a matter of time.
In the future, as .NET is available on more operating systems, servers will be available to run server based assemblies. Operating system and even CPU will no longer matter, and any server which has support for the .NET framework will be able to run assemblies written by developers using any other operating system.
Windows currently is based on the Win32 core. And the .NET framework runs on top of the Win32 core. However, in future editions of Windows, this relationship will blur and eventually reverse. This is very similar to how Windows 3.1 evolved into Win32.
In the future, Microsoft will ship an operating system that *is* .NET. Drivers and trusted code will still be permitted to run at a high level to provide hardware and other necessary support. However, unmanaged applications will run in a compatibility environment which simulates the Win32 API and translates to the .NET framework. This is similar to how Windows 3.1 applications are run on Win32.
The ultimate goal for every application is to become a managed application. While this may seem very far fetched, if we look back at history, it is not. In the days of Windows 3.1 or even DOS, it seemed a far dream to have all Win32 applications. However today, very few users are still using Win3.1 or true DOS applications (not to be confused with Win32 console applications). And it's very rare to find any developer still developing code for such environments.
.NET does require some reeducation and alterations of developer mentality. But the same change existed when developers moved from DOS to an event driven environment like Windows. Some time must be allowed for relearning, but the time invested will quickly pay off.
Writing safe code enforces new restrictions on developers and requires some reeducation to learn new techniques. But these new techniques are best of breed practices that application developers should have been using before, but either did not, or could not use. .NET helps to enforce these best practices.
It's hard to summarize this whole article. The article itself was a summary. So instead, let's consider some comparisons.
Win32 code is like a 1950's corvette. All soaped up and a lot of raw horsepower. You can go in and monkey with the engine and make easy modifications. You can pop it out of gear. You can shift into first gear while doing 100 miles per hour, if you want.
.NET is a 2004 corvette. Still lots of horsepower, but now you have seat belts, computer controlled engine, airbags, anti lock brakes, and safety glass.
As an antique, the 1950's corvette certainly has some appeal. But in developing software, not many of us fondly look back at punch cards or DOS windows. So, that leaves safety and capability. Cars certainly do not crash as often as software does. If they did, the human race would be in a steep population decline. So, let's assume that cars did crash just as often and that frequent and even serious crashes were common. Which car would you prefer to drive?