What s Different in the Revised Language Definition?

The Declaration of a Managed Class Type



In the original language definition, a reference class type is prefaced with the __gc keyword, where the gc is an acronym for garbage collected. In the revised language, the __gc keyword is replaced by one of two spaced keywords: ref class or ref struct, where ref is an abbreviation for the .NET reference type. (This was a rather acrimonious if minor change. The change from gc to ref is intended to provide a symmetry with the use of value to declare a value class type, the two primary limbs of the .NET unified type system.) As with native C++, the choice of struct or class indicates the public (for struct) or private (for class) default access level within an initial unlabeled portion of the type body. For example, the following pair of class declarations, in the original language,


// original language syntax

            public __gc class Block { & };      // reference class

      public __value class Vector { & };  // value class


under the revised language design are equivalently declared as follows:


// revised language syntax

      public ref class Block { & };

      public value class Vector { & };


[Warning: Digression Altert] An interesting digression is to ask the question, why did Stroustrup add class to the C++ language design? There is no real necessity for its introduction since the C-language struct is extended within C++ to support everything that is possible to do with a class. I have never asked Bjarne about this, so I have no special insight, but it is an interesting question and seems somewhat relevant to the topics of declaring an abstract and sealed class.


One possible answer I call it the foot soldier shuffle is to argue that, no, the introduction of class was absolutely necessary. After all, not only is the default member access different between the two keywords, but so is the access level of the derivation relationship as well. So of course how could we not have both?


But back then of course introducing a new keyword that is not only incompatible with the existing language but imported from a different branch of the language tree (Simula-68) risked offending the C-language community. Was the difference in implicit default access rules really the motivation? I can t convince myself of that.


For one thing, the language neither prevents nor warns if the designer using the class keyword makes the entire implementation public. There is no policy in the language itself with regard to public and private access, and so it hardly seems reasonable to suggest that the default unlabeled access levels permissions is considered an important property that is, important enough to outweigh the cost of introducing an incompatibility.


Similarly, the wisdom of defaulting an unlabeled base class to private inheritance seems questionable as a design practice. It is both a more complex and less understood form of inheritance since it does not exhibit type/subtype behavior and thus violates the rules of substitutability. It represents a reuse not of interface but of implementation, and having private inheritance be the default is, I believe, mistaken.


Of course, I couldn t say that in public because in the language marketplace, one should never admit one iota of imperfection in the product, since that is providing fodder to the enemy who will be swift to seize on any competitive advantage to gain market share. Ridicule is particularly popular in the intellectual niche. Or, rather, one doesn t admit imperfection until the new, improved product is ready to be rolled out. 


What other reason could there be for the introduction of the class incompatibility? The C-language conception of a struct is that of an abstract data type. The C++ conception of a class (well, of course, it did not originate with C++) is that of a Data Abstraction, with its accompanying ideas of encapsulation and interface contract. An abstract data type is just a contiguous chunk of data associated with an address point to it, cast it about, pick it apart, and move on swiftly. A data abstraction is an entity with lifetime and behavior. It s of pedagogical significance, because words make a world of difference at least within a language. This is another lesson the revised design takes to heart.


Why didn t C++ just drop struct altogether? It is inelegant to retain the one and introduce the other, and then literally minimize the difference between them. But what other choice was there? The struct keyword had to be retained, because C++ had to be as closely backward compatible with C as possible; otherwise, not only would it have been less popular with the existing programmer base, but it probably would not have been allowed out the door. (But that s another story for another time and place.)


Why is a struct by default public? Because otherwise existing C programs would not compile. That would be a disaster in practice, although one would certainly never hear that mentioned in Advanced Principles of Language Design. There could have been an imposition within the language to impose a policy such that the use of struct guarantees a public implementation whereas the use of class guarantees a private implementation and public interface, but that would serve no practical purpose and would therefore be a bit too precious.


In fact, during testing of the release of the cfront 1.0 language compiler from Bell Laboratories, there was a minor debate within a small circle of language lawyers as to whether or not a forward declaration and subsequent definition (or any such combination) had to consistently use the one or other keyword, or should they be allowed to be used interchangeably. If struct had any real significance, of course, that would not have been allowed. [Warning: Digression Altert All Clear]



How Do We Declare an Abstract Class Type?


Under the original language definition, the keyword __abstract is placed before the class keyword (either before or after the __gc) to indicate that the class is incomplete and that objects of the class cannot be created within the program:


// original language syntax

public __gc __abstract class Shape {};

      public __gc __abstract class Shape2D: public Shape {};


Under the revised language design, the abstract contextual keyword is specified following the class name, serving as a kind of adjective.


// revised language syntax

public ref class Shape abstract{};

public ref class Shape2D abstract: public Shape{};


Of course, the semantic meaning is unchanged.



How Do We Declare an Sealed Class Type?


Under the original language definition, the keyword __sealed is placed before the class keyword (either before or after __gc) to indicate that objects of the class cannot be inherited from:


            // original language syntax

public __gc __sealed class String {};


Under the revised language design, the sealed contextual keyword is likewise specified following the class name:


            // revised language syntax

public ref class String sealed{};


One can also specify a class as both abstract and sealed, although on first blush that would seem illogical this is a special condition that indicates a static class, or, named scope. This is described in the CLI documentation as follows:


A type that is both abstract and sealed should have only static members, and serves as what some languages call a namespace.

For example, here is a declaration of an abstract sealed class under the original language design,


// original language syntax

public __gc __sealed __abstract class State



      static State();

      static String* version();



      static String* ms_version;



and here is the revised declaration,


            // revised language syntax

public ref class State abstract sealed



      static State();

      static String^ version();



      static bool ms_inParam;



If you have your managed design cap on, of course, your first impulse would be to write me and ask why version is not a property rather than an independent read access method. However, if, like me, you have doffed your blog design beret, you would reply, because, silly, we haven t as yet introduced properties, and I want to give them all the attention they deserve. Cheers.


disclaimer: This posting is provided "AS IS" with no warranties, and confers no rights.