C#, the natural progression

With Visual J++ in the dumpster, Microsoft introduces C# to fill the void

July 31, 2000 -- Microsoft's new vision of the Internet is a far cry from today's network of online content. Microsoft views the future Internet as a world of interrelated services that are developed by different individuals, written in different languages, deployed on different types of hardware, and hosted by different Internet operating systems.

The company's offering for this brave new world is the .Net platform. Actually, .Net is not a platform in the traditional sense; it is not a common hardware or software system. Instead, .Net is a collection of protocols that allow Internet applications to take advantage of disparate services running on different machines.

One direct result of Microsoft's new strategy is that the next version of Microsoft Visual Studio will feature retooled languages, modified explicitly to support the .Net platform. Java will be missing from the package, as Visual J++ is being discontinued. Not to worry, though; Microsoft will be introducing a new language, called C#, to fill the void. The company has assigned its best resources, including star language specialist Anders Hejlsberg, to C#'s development.

Suitably controversial: Anders Hejlsberg, the language architect

Given Hejlsberg's history, it's no surprise that Microsoft would entrust this endeavor to him. After all, C# will not be his first attempt to revolutionize the software-development landscape.

As chief architect at Borland, Hejlsberg secretly turned Turbo Pascal into an object-oriented application development language, complete with a truly visual environment and superb database-access features. Once touted as the "VB killer," Delphi has remained a cornerstone product for Borland (now Inprise/Borland).

When Microsoft hired Hejlsberg, luring him with a generous salary, stock options, and a large sign-on bonus, Borland sued for unfair recruiting practices. Borland also claimed -- providing few details to support the accusation -- that Hejlsberg was working on "Delphi for Java." This suit was eventually settled in Borland's favor; by that time, however, Microsoft had put Hejlsberg to work.


TEXTBOX_HEAD: Microsoft's goals for C#

  • Rapid application development (RAD) capability
  • Cross-platform deployment
  • Platform-native resource access
  • Support for the COM and .Net platforms


Hejlsberg beefed up Microsoft's Java offering; among other things, he artificially propelled its version number from 1.1 to 6.0 in one release in order to keep it current with the versioning of other Visual Studio languages. In fact, this leapfrogging of version numbers did not exaggerate the differences between 6.0 and its predecessor. Hejlsberg had added features that turned the language into a powerful Windows application-development platform. Additions included access to the Windows API; consequently, programs that took advantage of new features were not portable.

Hejlsberg's changes to Microsoft's offering prompted Sun to sue Microsoft for Java license violations. Instead of keeping the Java platform neutral, Sun claimed, Visual J++ language extensions locked developers into the Microsoft platform. Despite the fact that Microsoft's Visual J++ is arguably the best Java compiler, and that the company's virtual machine (the runtime module that executes Java bytecode) is one of the fastest available, Sun's suit has effectively prevented Microsoft from competing in the Java arena.

Microsoft has responded by pulling back from Java altogether, replacing it with a new cornerstone Internet platform -- .Net -- and a new banner language -- C#. Anders Hejlsberg is the natural choice to front the latter effort.

Justifying a new programming language

Some of the recent press concerning C# contends that developers will not accept yet another programming language. While it is true that several useful languages are already available to developers, there is room for one more -- provided it meets still-unfulfilled needs. A new language is, after all, just another tool that professionals can use to create software solutions. Let's examine the goals that Microsoft has set for C#, and the ways in which other languages to date have not met them.

  • Rapid application development: One of Microsoft's most significant goals for C# is support for RAD. Internet applications must be developed in Internet time; a new language must be easy to learn and debug, and must produce code that is easy to update. While Delphi and VB excel in these areas, C++ has not been quite as successful. The language itself is complex and difficult to master, and few useful C++ libraries provide simple interfaces. In addition, C++'s manual memory management and complex type-casting model make it difficult to debug.

    Furthermore, as we will see below, C++ does not inherently protect against potential problems caused by version incompatibilities. Despite all the effort that Microsoft and Borland have put into the language, C++ is still not suitable for rapid application development.

  • Cross-platform deployment: Internet languages should, by definition, support cross-platform deployment. Because the Internet is a network of disparate systems, services must be deployed to a wide range of hardware and software. Furthermore, client-side software should be capable of running on several types of devices, including PDAs and cell phones. Such flexibility is a challenge for virtually all languages, with the exception of Java. VB in particular produces only Windows applications for Intel-based machines. Delphi, too, suffers the same restriction. Delphi for Linux will be available soon, but it does not yet provide support for Internet appliances. Neither VB nor Delphi meets the goal of cross-platform deployment.
  • Access to platform-native resources; According to Microsoft, developers demand access to platform-native resources. Such access is sometimes necessary for writing powerful targeted applications. Visual J++ 6.0 granted developers access to the Windows API, which Java in general does not allow. Instead, Java provides for cross-platform deployment by defining a lowest common denominator standard that every virtual machine implements. Java developers must write to this weaker standard instead of taking advantage of more powerful services offered only on certain platforms. Thus, Java fails to meet the goal of providing access to platform-native resources.
  • Support for the COM and .Net platforms: Microsoft has identified support for the COM and .Net platforms as C#'s most important goal. Naturally, no other language currently supports the .Net platform, as it is still under construction. Unlike .Net, COM has been around for quite some time, but it nevertheless lacks strong language support. Most languages, C++ and Delphi included, require that developers create an additional IDL declaration, a class factory, and special embellishments for each COM object they create.

    Some language vendors have provided wizards that automate many common COM and OLE tasks, but these tools do not completely hide the complexity of COM. VB does successfully hide COM's complexity, but only by sacrificing power. VB doesn't only lack the power of an object-oriented language; it also fails to support low-level COM functionality -- multiple interfaces, aggregation, and custom marshaling, for example. In short, no existing language supports COM as comprehensively as C# does.

While these four goals are fairly lofty for a new language, Hejlsberg has drawn from the best of his experience in his efforts to make sure that C# achieves them. The result is a language that draws from Java and Delphi as much as, if not more than, it draws from C and C++. Note that the information that follows is based on the C# working spec, and may not accurately represent the final product release.

C# is a RAD environment

  • C# provides Java-style garbage collection: One of the most significant RAD features that C# provides is Java-style garbage collection. At arbitrary intervals during runtime, all unreferenced objects are automatically deleted. By relieving the developer of manual memory-management tasks, garbage collection makes program development easier and less prone to error. Automatic garbage collection, however, is time-consuming and unpredictable. C# therefore allows developers to disable garbage collection locally -- by marking code as unsafe -- in situations where realtime performance is required.
  • C# implements a Java- and Delphi-style value/reference-type system: To further support RAD, C# does away with the C/C++ pointer model in favor of a Java- and Delphi-style value/reference-type system. In this system, built-in types (integer, real, string, and so on), enumerations, and structures are all value types. The assignment and comparison operators copy and examine the values of these types of variables. Interfaces, classes, and delegates (described later) are all reference types. The assignment and comparison operators copy and examine the identity of the objects to which these types of variables refer.

    This value/reference-type system is much simpler than the C++ pointer model. It makes for much easier object manipulation and eliminates many of the memory bugs that plague C and C++ programs.

  • C# interfaces are declared independently of classes: C# also supports a Java- and Delphi-like interface model, in which interfaces are declared independently of classes. This stands in contrast to the C++ model, in which interfaces are actually abstract base classes. Both interfaces and classes may inherit multiple interfaces. While classes may inherit one base class, interfaces cannot inherit classes at all. This model avoids C++'s multiple-inheritance problem, in which implementations in different base classes can conflict. The need for complex mechanisms such as virtual inheritance and explicit scoping is also thereby eliminated. C#'s simplified interface model helps speed application development.
  • Declaration and definition of class methods are combined: Another way that C# simplifies development is by combining the declaration and definition of class methods, much as Java does. C++ developers must maintain separate files for declarations (the header file) and definitions (the implementation file), complicating the software development process. Relieving the developer of one more chore, C# even automatically discovers relationships among source modules. Where C++ requires #include (and Delphi requires uses), C# needs no additional input to locate related source files.
  • C# uses method references, called delegates, instead of method pointers: C# uses method references to quickly connect objects and methods. Called delegates, these method references are similar to Delphi's procedural types. Hejlsberg introduced this same mechanism into Visual J++ 6.0, though it is not part of the standard Java specification. Method references are somewhat similar to C++ method pointers, but are far more elegant, safe, and useful.

    A delegate is a reference type that holds a method's signature. An application can assign any method that matches this signature to a delegate variable. When this delegate variable is invoked, the associated method is called. Unlike Delphi procedure types, C# delegates automatically support multicasting. An application can assign many methods to one delegate variable; when the variable is invoked, all methods are called.

  • C# uses Java's mechanism for simple thread synchronization: To implement thread synchronization in C#, a developer simply marks the blocks of code that are critical. Where a Java developer would use the synchronized keyword, a C# developer uses lock. A hidden mutex wraps the marked block, allowing only one thread to execute the code at any given time. Differing keywords aside, this mechanism is the same in both C# and Java. Because threading is one of the most error-prone of all programming tasks, any feature that simplifies synchronization aids in rapid application development.
  • Explicit override declarations: Finally, C# uses explicit override declarations in support of RAD. Explicit override declarations support rapid application development by protecting classes' method namespaces and exposing accidental naming conflicts.

    A developer of a derived C# class must explicitly mark a method override with the keyword override, just as he or she does when working with Delphi. If a derived class includes an unmarked method that has the same name as a virtual method in the base class, the compiler cannot unambiguously discern the author's intent.

    On the one hand, a naming conflict could very well be accidental; this is especially likely if the base class and derived class were implemented independently by different programmers, perhaps working for different companies. In such a case, the compiler will issue a warning and treat the derived class method as a new declaration, not as an override.

    If, on the other hand, the developer has consciously chosen to use a name for a new method in a derived class that is the same as the name of a virtual method in a base class, he or she can include the new keyword to prevent a warning from the compiler.


TEXTBOX_HEAD: Features provided by C#

  • RAD features

    • Makes use of Java-style garbage collection
    • Makes use of Java- and Delphi-style value/reference-type system instead of pointers
    • Interfaces are declared independently of classes
    • Combines declaration and definition of class methods
    • Uses method references (similar to Delphi's procedural types) to quickly connect objects and methods
    • Makes use of Java's mechanism for simple thread synchronization
    • Makes use of Explicit override declarations
  • Other

    • Runtime component works much like a Java virtual machine
    • .Net runtime grants programmatic access to platform-native resources
    • Attributes provide support for both the COM and .Net platforms

C++ features not implemented in C#:

  • Scoping operator
  • Dereferencing accessor
  • Reference-declaration syntax
  • Templates


Other C# features

Considering all the language features just discussed, strong support for RAD appears to be one of Microsoft's most significant goals for C#. There are other important development needs, however, that C# must address. These include cross-platform deployment, access to platform-native resources, and support for the COM and .Net platforms. Let's examine the C# language features intended to support these demands.

  • Cross-platform deployment: C# solves the problem of cross-platform deployment the same way that Java does. The C# compiler generates a bytecode stream that is interpreted by the .Net runtime. The runtime component works much like a Java Virtual Machine; an application can be deployed to any device to which the .Net runtime has been ported.
  • Application access to platform-native resources- Unlike the Java virtual machine, however, the .Net runtime grants programmatic access to platform-native resources. A C# program can, for example, take advantage of the Windows API to run as a full-featured application on Windows 2000. The same program can also run on a PDA by using the Windows CE API subset. Naturally, not all of the services that the application might expect will be available on all devices. It is therefore the developer's responsibility to test the software on all target platforms, and to write special-case code, if necessary, that will allow the system to function in the absence of expected services.
  • Support for COM and .Net: To support both the COM and .Net platforms, C# includes a unique language feature called attributes. An attribute is actually a C# class that embellishes source code in order to provide metainformation. Attributes allow C# to support specific technologies such as COM and .Net without cluttering the language specification itself.

    For example, C# provides attribute classes that convert C# interfaces into COM interfaces. Others convert C# classes into COM coclasses. No IDL or class factory is necessary for performing these conversions. Some language observers have stated that all C# classes are COM objects. This is not true -- but with the proper attributes, any C# class can easily be exposed as a COM object.

    Another attribute library provided with the compiler wraps C# classes and functions as Web services. A Web service is a hosted software module that is callable over the Internet through an interaction protocol such as SOAP. SOAP wraps method calls, along with their parameters and return values, in XML data packets. Web services can be written in many languages and deployed to many hardware and software platforms. Moreover, different kinds of Web services can cooperate to make up an entire Web application. Using the proper attributes, a programmer can easily turn any C# class or function into a Web service.

Features not found in C#

Consistent with Anders Hejlsberg's history, many of the features that C# uses in support of Internet applications are culled from Delphi and Java. Yet Microsoft claims that C# descends from C and C++. Let us therefore examine some of the C++ features that are missing from C#.

  • Scoping and dereferencing operators: C# does not use the C++ scoping operator (::); instead, it relies upon the Delphi and Java equivalent, the dot operator (.). Furthermore, because it is based on the Java- and Delphi-style value/reference-type system described earlier, C# does not in most cases use the C++ dereferencing accessor (->). Instead, it again implements the dot operator. While the overloaded dot operator may confuse C++ programmers who are just learning C#, it will be quite familiar to Java and Delphi developers.
  • Reference declaration syntax: Because class, interface, and delegate types are references by default, C# lacks the reference declaration syntax of C++. Instead, the new language uses a syntax similar to Delphi's for declaring pass-by-reference parameters:

    • An unmarked parameter is input
    • The ref keyword indicates an input/output parameter (similar to Delphi's var)
    • The out keyword indicates an output parameter
    • The params keyword indicates a variable-length parameter list (similar to Delphi's variant open-array parameters)
  • Templates: Like Java and Delphi, C# does not have templates. Consequently, it has no mechanism to support the type-safe declaration of collections. Instead, every class is ultimately derived from the common base class object. A generic collection class must be a collection of objects, requiring an unsafe downcast of its members to the desired type.

Still, even without these C++ language features, C# is a powerful programming language, designed around Java- and Delphi-like features to support Internet applications. C++, because of its machine-level focus and its lack of RAD support, would not have been an appropriate basis for an Internet application-development language. Any C++ developer who needs to write applications and services for the .Net platform will be well advised to learn C# when it is released -- remembering that it differs more from C++ than its name might suggest.

In the interim, it may be best to learn Java or Delphi. Not only will these languages get you one step closer to an understanding of C#, they are also useful languages in their own right. As software professionals, we should take advantage of the best tools available.

Michael L. Perry has been a professional Windows developer for over six years and maintains expertise in COM+, Java, XML, and other technologies currently shaping the programming landscape. He formed Mallard Software Designs in 1998, where he applies the mathematical rigor of proof -- establishing the correctness of a solution before implementing it -- to software design.

Learn more about this topic