The Declaration of a Managed Class

What s Different in the Revised
Language Definition?

The Declaration of a Managed Class



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,
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
or private (for
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
Vector { & };  //
value class


under the revised language design are equivalently
declared as follows:


// revised
language syntax

      public ref class Block
{ & };

      public value
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



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

public ref class Shape2D
abstract: public Shape{};


Of course, the semantic meaning is unchanged.



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


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. 




Comments (5)

  1. Lonnie McCullough says:

    I think the differences you make between structs and classes explains everything about why they are both in the language. Like you say "words make a world of difference." Data Abstraction is overkill sometimes and its nice to be able drop all that baggage for a good old fashioned value type (abstract data type == figure out the offsets for me)!

  2. stan lippman says:

    Well, of course, this is what those other folks bash us folks about 🙂