Topic: Polymorphic Arguments -- An Informal Proposal


Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Wed, 12 Aug 92 20:10:36 GMT
Raw View
The following proposal is informal and incomplete. It is proposed for
the purpose to give some hints to solve some major problems in the
current C++. I have not enough spare time to make a complete
investagation, if someone is interested or happened to have the
similiar thought, please let me know.

A constant, variable, parameter, reference, or pointer can be
polymorphic. We call them polymorphic arguments.

A polymorphic argument specified by class C can represent an
object of class C or one of its derived classes.

We call a non-polymorphic argument a type exact argument. A type
exact argument can accept an object of a derived class with a
conversion (slicing) to its exactly specified type.

In the present C++, a constant, a vriable, or a parameter is
a type exact argument. A class pointer or class reference is
a polymorphic argument.

In extended C++, we will have polymorphic constant, variable,
and parameter:

   poly Animal a;
   const poly Animal a,  // usually as a function parameter

and we will have type exact pointer and reference:

   Animal sealed * ap;
   Animal sealed * af;

Type exact pointer or reference cannot accept a value of pointer
or reference of derived classes. For example, "ap=aMammalPointer"
is invalid, and slicing will be made for "*ap =aMammal".

We should distinguish a polymorphic pointer from a pointer to a
polymorphic argument:

   poly Animal * ap;

is a pointer to a polymorphic argument, but pointer itself is not
polymorphic. However,

   Animal * ap; // it is "Animal poly * p" by default

is a polymorphic pointer but the argument pointed by the pointer
is not polymorphic.

Why should we distinguish a polymorphic argument from a exact
argument? Let us first consider the general implementation issues:

(1) For a polymorphic argument, we need combine a type reference
with the object code.

(2) For a type exact argument, only object code is presented.

Therefore, we can

(1) Integrate the convensional C types into class hierarchy
without sacrifying the space and the speed, since convensional
C arguments are not polymorphic, and we need not to combine a
type reference with them. For example, if we treat "int" as a
class,

   int i;

is still 4 byte (for 32bit machine) long.

(2) Implement a complete RTTI without the overhead on space if you
do not use them. The type code is included into the run time code
only when you use it with a polymorphic argument. For example, the
type code for "int" class is included into run time code (at link
time), only when you write the following code:

   poly number np;
   ...
   np = anInteger;

Therefore, each type or class has a type code but not necessarily
to be included into run time type code if you do not use it with
polymorphism.

(3) Implement sizeof(), typeof() of a polymorphic argument correctly.
Since each type will have a code, we can include two standard fields
in the type code, one is the unique (project-wide) type identifier
(can be an integer), the other is the real size of the object code.
(Here we can take the advantage of the fact that the type code is
linked into the run time code only for those types associated with
polymorphism.)

(4) Implement increment and decrement of pointers correctly (the
same reason as we can implement a correct sizeof()).

(5) Save the storage for homogeneous object container. For example,

    Animal * p;
    Dog da[1000];
    Cat ca[20000];

In current C++, if Animal has virtual functions, "da" will have
additional 4K bytes and "ca" will waste 80K bytes! It is really
not necessary to tag all objects in a homogeneous object container
since they are all in the same type. Now, since we only tag those
polymorphic arguments, we need only tag the polymorphic pointer p.
When

   p = da;

"p" get both the address of the "da" and the type of "Dog".
(When p++, p increases by the actual size of a dog.)

In case of one pointer vs. many heterogeneous objects, we
can use a polymorphic pointer to refer to many specific
non-polymorphic objects. Therefore, we can save much space.

In case of many pointers vs. one polymorphic object, we can
use non-polymorphic pointers to the polymorphic object. This
is the same struture in the current C++ implementation.

David Shang