From: shang@corp.mot.com (David (Lujun) Shang)
Subject: Re: The concept of templates considered ill designed
Reply-To: shang@corp.mot.com
Organization: Motorola, Inc., Software Research and Development, Rolling Meadows, IL. 60008
Date: Fri, 2 Oct 92 14:49:59 GMT

From: shang@corp.mot.com (David (Lujun) Shang)
Newsgroups: comp.std.c++,comp.lang.c++
Subject: Re: The concept of templates considered ill designed
Reply-To: shang@corp.mot.com

In article <1992Oct1.140643.9775@cadsun.corp.mot.com> shang@corp.mot.com I  
wrote:
> Template is not a self-enclosed type-safe language feature, i.e. it cannot be  
> compiled separately to ensure type-error free. All type errors about the 
> class parameters are checked when the template is used. When the 
> library-developers ship their products, they cannot ensure their templates 
> are type-error free. The library user will get confused when an error is 
> reported on the source code of the template: "should it be my fault or the 
> fault of the template itself?"
>

I'd like to add something more. When OO models are designed with many 
templates nested and derived, they really messed up the whole system 
if temaplates cannot be self-ensured type-correct. I've used templates 
to write many generic models. It's almost a nightmare for me to trace 
the error when templates are nested and with three or four derived 
depth in sperated files. It's okay for me because I'm both the template 
writer and the template user. But how about when the templates are 
shipped to users with a library? 
 
Another major defect with C++ template is that the template does not 
support specialization. I view specialization is as important as 
inheritance in OO design. We use template mainly for specifying an 
abstract class with some generic features. In most cases, these 
generic features are vague for a general tempalte. As special 
templates derived, the generic features becomes more and more 
clear. Therefore, template specification should be able to describe 
and  precise generic features step by step. Unfortunately C++ 
template applies unconstrained class parameters, which not only 
leaves tempalte an imperfect feature in sense of type-safeness, 
but also disables specialization.

Many models need specialization. Without language supported 
specialization, we have to use many nasty unsafe downcast in 
the program. The worse thing is that the programmers or the users 
must keep in mind that something has virtually been specialized but 
there is no way to protect them from passing a general object to a 
virtually specialized interface.

Can C++ templates be improved? Sure. The concept of constrained 
classes has been applied in some other OO languages. Why can't C++ 
apply it? Of cause there are some technical difficulties to integrate 
the concept of multiple inheritance and the concept of the 
constrained parameterization in C++. But it does not mean this 
integration is imppossible.

A constrained parameterized class is a self-enclosed type-safe entity. 
It can be compiled separately to ensure type-correctness.

A constrained parameterized class can be used as an abstract class. 
Its implementation be separated from its definition. The 
implementation code need not be exposed to the user, and the user 
need not the check the implementation code to locate the error.

Constrained parameterized classes support specialization, therefore,
MammalGroup<MemberType[Mammal]> is a specialized class of 
AnimalGroup<MemberTyep[Animal]>, you can specialize your template 
models step by step.

Constrained parameterized classes are real classes, and you can 
achieve polymorphism based on specialization (the current C++ can 
only achieve polymorphism on inheritance). For example, I need a 
generic object storage model like:


                          specialization
 Reference --------------------------------------------------------->
   |
   |      reference
  i|      |      |
  n|   pointer---|------ > pointer<list> --> pointer<ordered_list> ->
  h|       persistant_ref --> pref<list> --> pref<ordered_list> -->
  e|             |  (pref)
  r|             |
  i|      synchronized_ref --> sref<list> --> sref<ordered_list> -->
  t|             |  (sref)
  a|             |
  n|       recvorable_ref --> rref<list> --> rref<ordered_list> -->
  c|                (rref)
  e|
   |
   v

So that I can use user-defined references in the way I use built-in
pointers. For example, I can use MS Windows' memery handle like
(the following programs are not written in C++):

class Base { public: virtual void vfoo(); };
class Derived1: public Base { public: virtual void vfoo(); };
class Derived2: public Base { public: virtual void vfoo(); };

class Handle < class ObjType > 
      // unconstrained ObjType can be any type
{  protected:
      HANDLE h;
   public:
      ObjType * operator->() { ... }; // open the handle
      void * operator <-() { ... };   // close the handle
      thiscalss create( ObjType * ) { ... };  // create the handle
};
class BaseHandle: public Handle < class ObjType[Base] > {}; 
class Derived1Handle: public BaseHandle < class ObjType=Derived1 > {}; 
class Derived2Handle: public BaseHandle < class ObjType=Derived2 > {}; 

poly BaseHandle bh;  // a polymorphic handle, it must be initialized.
                     // BaseHandle is an abstract class, therefore
                     // "BaseHandle bh" is illeagal.
Derived1Handle d1h;
Derived2Handle d2h;
bh = d1h.create(new Derived1(...));
bh->vfoo(foo);  // should call class Derived1's vfoo
bh = d2h.create(new Derived2(...));
bh->vfoo(foo);  // should call class Derived2's vfoo

David Shang


Newsgroups: comp.std.c++