Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

C#, CLI (.NET), and C++/CLI Standardization


October, 2004: C#, CLI (.NET), and C++/CLI Standardization

Innovation, multiple implementations, and widespread support

Rex is an independent consultant, author, and editor of the C#, CLI, and C++/CLI Standards. He also worked on the ANSI and ISO/IEC standardization for C. He can be reached at rexrexjaeschke.com.


In recent years, international committees have been formed to produce Standards for C#, a new dialect of C++, and Microsoft's .NET Common Language Infrastructure (CLI) execution environment (a subset of the Common Language Runtime, or CLR). All three efforts are being conducted under the auspices of Ecma International (http://www.ecma-international.org/). These standards are being produced to encourage innovation, multiple implementations, and industry support. In this article, I report on the status of each effort and present an overview of the technical features involved.

C# (Ecma TC39/TG2)

Designed by Anders Hejlsberg, Scott Wiltamuth, and Peter Golde, C# debuted as part of a prerelease of Microsoft's .NET technology in July 2000. Although Microsoft's implementation of C# relies on the CLI for library and runtime support, other implementations of C# need not, provided they support an alternate way of getting at the minimum features required by the C# Standard. (In other words, as written, the C# Standard does not require the CLI.)

TG2 met monthly from November 2000 through September 2001. The resulting Standard is known as ECMA-334, 2nd Edition-December 2002 and ISO/IEC 23270:2003(E); see http://www.plumhall.com/ecma/index.html. (The Japanese national Standards body, JIS, has subsequently translated this Standard to Japanese.) In January 2003, work began on the next edition, and a revised Ecma Standard is expected in June 2005 with the ISO/IEC version to follow in September 2006. At least one beta implementation containing most (if not all) of the features in this became available in July. The main features of the C# (Ecma TC39/TG2) Standard are:

Generics. C#'s generics feature allows classes, structs, interfaces, delegates, and methods to be parameterized by the types of data they store and manipulate. (Users of generics in Eiffel or Ada, or users of C++'s templates, should easily be able to understand generics in C#.) The most obvious kind of type to parameterize is that of a collection class (such as a stack); see Example 1(a). To use this generic class, you specify the actual type of the elements you want, as in Example 1(b). And given a user-defined type Transaction, you can create a stack of those, too; see Example 1(c). It is important to note that a specific instantiation of a generic type is done at runtime.

The set of types that can be used to instantiate a generic type or method can be constrained. For instance, in Example 1(d), the class has a constraint containing two where clauses. The first requires that the type provided for KeyType must implement the interfaces IComparable and IEnumerable, while the second requires that the type provided for ElementType be of type Transaction or a derived type thereof. Failure to match any constraint requirement results in a compilation error.

Like types, methods also can be generic. In Example 1(e), for instance, this method lets you push multiple items onto a Stack of any kind, as in Example 1(f). In many cases, the compiler can deduce the type of the method based on the types used in the argument list, allowing the <...> notation on the method call to be omitted.

Static Classes. It is occasionally useful to define a class that is simply a home for a family of static methods and fields (System.Math is one such example). However, such a class must be made sealed and given a private "do-nothing" constructor to prevent instantiation. This can now be achieved by declaring the class to be static. A static class (Example 2) is quite restricted and cannot:

  • Have an explicit base class (it implicitly inherits from type object).
  • Implement any interfaces.
  • Contain any operators.
  • Contain protected or protected internal members.
  • Contain anything other than static members.
  • Be used as a base class.
  • Be instantiated.

A static class can be a member of a nonstatic class and vice versa.

Partial Declarations. At times, the declaration of a type can grow to be large, making it difficult—if not impractical—to keep it in a single source file. (Programs that generate C# source certainly can face this problem.) By splitting a type declaration into multiple source files, each file can concentrate on one or more semi-independent concerns; see Example 3. All of the parts of Window must be compiled together, and the member set is the union of all the members in all the parts.

Anonymous Methods. In certain situations, you need a small method that will only be called once, at most. Rather than defining that method with a name, when that name is really unimportant, you can define it as an anonymous method, directly in-line, in the place in which it is needed. You do this by creating a delegate to an unnamed method. In Example 4(a), you define an anonymous method that takes one argument of type int and returns a bool. In Example 4(b), the anonymous method is created, and that creation expression is used as an argument in a call to the method F. Note that the body of the anonymous method can access the parameters and local variables of the method that encompasses it.

Iterators. C# builds on the Clu programming language's notion of iterators via the foreach statement, which iterates over the elements of an enumerable collection. However, to be enumerable, a collection must have a parameterless GetEnumerator method that returns an enumerator. Enumerators can be difficult to implement, but with the help of iterators, the job can be significantly simplified.

An iterator is a statement block that yields an ordered sequence of value. Example 5 prints a simple multiplication table of the integers 1 through 10. Although the FromTo method is invoked only once to generate the enumerable e, e.GetEnumerator() is invoked multiple times (by the foreach statements) to generate multiple equivalent enumerators. These enumerators all encapsulate the iterator code specified in the declaration of FromTo.

Likewise, you can write GetEnumerator methods more easily for (generic and nongeneric) collection types such as stacks and linked lists.

C++/CLI (Ecma TC39/TG5)

When the first version of .NET was released in 2000, Visual C++ supported it via "Managed Extensions." These extensions involved the introduction of S-type string literals; numerous keywords starting with a double underscore; and support for the .NET's reference and value types, interfaces, properties, and delegates. Users of these extensions provided lots of feedback, so much so, that the second incarnation of this CLI binding looks quite different.

TG5 formed in September 2003 and began meeting every six weeks starting in November 2003; see http://www.plumhall.com/ecma/index.html. Its first Ecma Standard is expected in June 2005, with the ISO/IEC version to follow in September 2006. At least one beta implementation containing most (if not all) of the features in this new version became available in July.

Among the changes from Managed Extensions are:

  • S-style string literals are not needed (nor are they supported). The compiler handles the task of converting C-style string literals into strings of type System::String.
  • Pointers into the garbage-collected heap are now known as "handles," and they now have a notation separate from pointers. For instance, in Example 6, the "^" punctuator is used to indicate a handle. There is no implicit conversion between a pointer and a handle and vice versa. However, there is no corresponding unary operator "^"; to dereference a handle, you use the unary "*" operator, as with pointers. (Actually, this is advantageous when writing templates and generics that need to work with both pointer and handle types.)
  • As users of Managed C++ did not like the double-underscore-style keywords, after much debate, it was agreed to introduce as few new keywords as possible, to spell them without leading underscores, and to avoid conflicting with common naming idioms as much as possible. These new keywords are: enum class, enum struct, for each, gcnew, interface class, interface struct, nullptr, ref class, ref struct, value class, and value struct. (Note that some of these contain white space.)
  • Other facilities that were previously accessed via keywords are now accessible via "context-sensitive keywords"; that is, by identifiers that carry special meaning only in certain contexts. These identifiers are: abstract, delegate, event, finally, generic, in, initonly, literal, override, property, sealed, and where.

Among the main features of C++/CLI are:

Null Literals. The nullptr keyword was added to represent the null value constant. This value can be converted to any handle type, with the result being a null handle. It can also be converted to any pointer type, with the result being a null pointer.

Managed Arrays. An array that is allocated on the garbage-collected heap is a "managed array." It is declared using a pseudotemplate notation; see Example 7.

In the case of subscripting a multidimensional managed array, you use a set of comma-separated index values rather than multiple sets of [] each with one index. For this to work, the grammar for expressions inside [] was changed so that commas inside brackets are treated as punctuators rather than operators.

Literal and Initonly Fields. A literal field represents a compile-time constant rvalue. This value can depend on the value of other literal fields within the same program as long as they have been previously defined; see Example 8. (Of course, Standard C++ I/O can be used instead.)

Literal fields are only permitted in ref, value, and interface classes.

An initonly field is an lvalue only within the ctor-initializer (that is, after the optional colon following a constructor definition's parameter list) and the body of a constructor, or within a static constructor; otherwise, it's an rvalue. It lets an object be initialized during object construction or class initialization only.

Initonly fields are only permitted in ref and value classes.

Class and Function Modifiers. A class can have either of two modifiers: abstract or sealed; see Example 9(a). By declaring a class abstract, you avoid the need to declare any pure virtual functions; however, both approaches result in the same behavior. A sealed class cannot be used as a base class.

A member function can have the following modifiers: abstract, new, override, and sealed. A function with any of these modifiers must also be explicitly declared virtual; see Example 9(b).

An abstract function is an alternate way of saying it's a pure virtual function. The modifier new declares that the function does not override a function in the base class. (This helps with versioning, especially when new functions are added to existing base classes.) The sealed modifier declares that the function cannot be overridden in a derived class.

The override modifier not only allows a function to override a function having the same name in a base class, it also lets the names be different. An alternate way to achieve the same thing is to use an override specifier; see Example 9(c).

for each Statements. The for each statement enumerates the elements of a collection, executing a given statement for each element of that collection. For instance, the output of Example 10(a) is shown in Example 10(b). The simplest way for a type to be a collection is for it to implement the interface System::Collections::IEnumerable. All the standard collection classes do this, as does the pseudotemplate type array.

try/finally Statements. A try block can have an optional finally block, provided it follows all catch blocks. The finally block is executed after its corresponding try block terminates normally or abnormally, even in the presence of exceptions that are thrown up the function call tree past the function containing the finally block.

Enums. There are now two forms of enum: native and CLI, the latter being declared using enum class (or enum struct). For both forms, the underlying type can be stated explicitly and they can be made public or private with respect to their parent assembly. Additionally, both forms are derived from System::Enum, allowing access to a variety of interesting member functions. For instance, Example 11(a) produces the output in Example 11(b). Why have two different forms of enum when they seem to support the same capabilities? The CLI form allows interoperability with other CLI-based languages, whereas the native form does not.

Generics. The generics feature allows classes, structs, interfaces, delegates, and methods to be parameterized by the types of data they store and manipulate, much like templates. However, with generics, a specific instantiation of a generic type is done at runtime rather than at compile time; see Example 12(a). The set of types that can be used to instantiate a generic type or method can be constrained. In Example 12(b), the class has a constraint containing two where clauses. The first requires that the type provided for KeyType must implement the interfaces IComparable and IEnumerable, while the second requires that the type provided for ElementType be of type Transaction or a derived type thereof. Failure to match any constraint requirement results in a compilation error.

Like types, functions also can be generic. With Example 12(c), you can push multiple items onto a Stack of any kind, as in Example 12(d). In many cases, the compiler can deduce the type of the function based on the types used in the argument list, allowing the <...> notation on the function call to be omitted.

The ... notation preceding the array parameter is new, indicating that the parameter following it is a "parameter array," the CLI type-safe equivalent of varargs.

Liaison with the Standard C++ Committee

As C++/CLI is specific to the CLI, its Standard is being produced by a sibling to the Ecma committee that is standardizing the CLI itself. However, the C++ Standard is maintained by committee ISO/IEC JTC 1/WG 21. C++/CLI is not being defined in isolation from Standard C++; quite the contrary. All TG5 documents are made available to WG21 members, a joint TG5-WG21 e-mail reflector handles technical discussions, and WG21 members are invited to attend TG5 meetings. A number of C++/CLI's innovations have been submitted to WG21 for its consideration as additions to a future version of the C++ Standard.

CLI (Ecma TC39/TG3)

The CLI programming environment consists of three main parts: a Virtual Execution System (VES), metadata having a portable format, and an extensive library. (Not all of the .NET library types have been standardized as part of CLI. For example, serialization, database access, and GUI support are not included.) From the programmer's viewpoint, CLI (and .NET) is simply the "engine under the hood," which manifests itself via programming language extensions and runtime library support.

TG3 met monthly from November 2000 through September 2001. The resulting Standard is known as ECMA-335, 2nd Edition-December 2002 and ISO/IEC 23271:2003(E). A companion Technical Report is Ecma Technical Report TR/84, 2nd Edition-December 2002 and ISO/IEC 23272:2003(E). (JIS is working on a Japanese translation.) In January 2003, work began on the next edition. A revised Ecma Standard is expected in June 2005 with the ISO/IEC version to follow in September 2006. At least one beta implementation containing most of the features in this new version became available in July.

TG3 has been working on a number of issues: editorial improvements, tightening of terminology and technical specification, and the addition of new features. The main features are:

Generics. TG3 generics allows types and methods to be parameterized by the types of data they store and manipulate, much like generics in Eiffel or Ada and templates in C++. The set of types that can be used to instantiate a generic type or method can be constrained. (For examples of generic types and methods, and examples of constraints, refer to the previous C# and C++/CLI discussions.)

The addition of support for generics required new virtual machine instructions, new metadata tables, and an extensive set of new library types and new methods on existing types. The new library types include support for the following kinds of collections: dictionary, list, queue, and stack.

Debugging Information Interchange. A Debugging Information Interchange specification for portable CILDB files provides a standard way to interchange debugging information between CLI producers and consumers. This specification serves to fill in gaps not covered by metadata, notably the names of local variables and source-line correspondences.

Imprecise Faults. Some Common Intermediate Language (CIL) instructions perform implicit runtime checks that ensure memory and type safety. Originally, the CLI guaranteed that exceptions were precise, meaning that program state was preserved when an exception was thrown. However, enforcing precise exceptions for implicit checks makes some important optimizations practically impossible to apply. You can now declare, via a custom attribute, that a method is "relaxed," which says that exceptions arising from implicit runtime checks need not be precise. Relaxed methods preserve verifiability (by preserving memory and type safety) while permitting optimizations that reorder instructions.

Parallel Library. The purpose of the parallel library is to provide easy parallelism for nonexpert programmers so that multithreaded CPUs can be exploited. The profile stresses simplicity over large scalability. To use this facility, a CLI-based language must support delegates.

Further Reading

The C# Programming Language. Anders Hejlsberg, Scott Wiltamuth, and Peter Golde, Addison-Wesley, ISBN 0321154916, 2004.

The Common Language Infrastructure Annotated Standard. James S. Miller and Susan Ragsdale, Addison-Wesley, ISBN 0321154932, 2004.

.NET Framework Standard Library Annotated Reference. Brad Abrams, Addison-Wesley, ISBN 0321154894, 2004.

Acknowledgments

Thanks to Jon Jagger, Joel Marcey, Jim Miller, Tom Plum, Herb Sutter, and Jan van den Beld for their help with this article. A small amount of text and code appearing in this article was taken from the draft C#, CLI, and C++/CLI Standards.

DDJ


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.