From: shang@corp.mot.com (David (Lujun) Shang)
Subject: Re: run-time type checking (was: Re: Covariant Types in Derived Classes)
Reply-To: shang@corp.mot.com
Organization: Motorola, Inc., Software Research and Development, Rolling Meadows, IL. 60008
Date: Wed, 22 Jul 92 02:22:18 GMT

In article <1992Jul21.162659.25474@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU  
(John MAX Skaller) writes:
> 	In general C++ programming I do not agree that it is
> necessary to recover arbitrary type information. That is because,
> quite simply, you CANNOT use it.
>
"In general C programming I do not agree that it is necessary to use  
inheritance of structure. That is because, quite simply, you CANNOT use it"
-- I don't like the argument. We are not talking about C++ programming. We are  
talking about the enhancement of the C++. If this argument could make any  
sense, why should we need C++?

In article <1992Jul20.215058.1216@cadsun.corp.mot.com> I write:
> >What I disagree is  
> >the argument that the design of heterogeneous collection is fundamentally  
> >wrong, which, of cause, is not your statement.
>

In article <1992Jul21.162659.25474@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU  
(John MAX Skaller) replies:
> 	I think I should clarify here: I am arguing against
> DOWNCASTING. 
> 
I am against *unsafe* downcasting too. What we are arguring about is not the  
downcasting. It is the run time type checking: whether it is necessary.

> 	I am not against collections of objects all derived
> from a common base provided you access them via the base.
> That is the vey point of inheritance, after all.
> In this case the objects are all of the same type:
> it is homogeneous at the level it is accessed and
> heterogeneous at the actual object level, but the actual
> object level is not accessible.
>
True. I'm always in favor of doing that. We can always add member funtions and  
virtual member functions to aviod downcasting an element in a *domestic*  
heterogeneous collection or structure. But this does not mean that the run time  
type info is not necessary. In case of a foreign heterogeneous collection, we  
often need the run time type info, need to store and export the type info  
together with the object. 

> 	I am not against collections of objects of completely
> unrelated types provided the types are drawn from a finite
> and statically known set. In this case there is a 'type' which
> is the finite union of those types, so again, the collection
> is really homogeneous wrt that type.
>
This case exactly examplifies the necessity of runtime type info. Given an  
element in this collection, you need run time type info to identify its type.  
Otherwise, how do you do with the element which may be in one of the types that  
are *completely unrelated*, say { int, float, doulbe }?

> 
> 	I am against using, in general programming,
> DOWNCASTING or run-time type information to defeat the type system.
>
I just don't understand! Run time type check is a facillity to prevent careless  
downcast to defeat the type system. How can you say that it is used in general  
programming to defeat the type system?
 
> 	I agree that in Debuggers and other such programs
> these facilities are essential, indeed, you need much more
> than a mere safe downcast or run-time type code. In a debugger,
> for example, you need in effect run-time access
> to the complete declaration and definintion of each class in
> the whole program!
>
A simple type id can be a key for a debugger to access to the complete  
declaration and definintion of each class in the whole program. We are not  
necessary to include the complete type information at run time.

> 	C++ does NOT have facilities at present to do this.
> I am NOT against adding them. But I would be against using these
> facilities in the general programming context for which C++
> was intended and where such mechanism are *dangerous*.
>
Again, I can't understand. Run time type check is not a dangerous mechanism. On  
the contrary, it is used prevent potential dangers.
  
> 	Clearly, for example, a debugger which allows you
> to modify instances of a class breaks encapsulation!
> It breaks almost every principle you can think of. 
> It is meant to: you use the debugger when a more important
> thing is already broken : your program :-)
> 
Here, you goes too far. A debugger can break every principle of encapsulation  
and protection only through low level programming facillities (e.g. the bitwise  
and bytewise read/write, enforced typecasting between different types, machine  
addresses, etc.). But a debugger can never break any principle of encapsulation  
and protection only through run time type check. Remember: run time type  
checking does not allow to cast objects which are actually of different types.

Even we stick to homogeneous programming, we still need run time type checking.  
One of your reason against the concept of "thisclass" is that it needs run time  
type checking, which you view as a disadvantadge. "thisclass" is just a  
facillity to describle homogeneous data structure.

Okay, let's get rid of the concept of "thisclass" for the time being. Now, is  
it true that run time type checking is no longer needed for homogeneous data  
structure? No. Without covariant type specification (now, we come to our  
original subject) in derived classes, we still have to run time type check the  
type of arguments in derived classes in order to prevent any violation. Let's  
consider a homogeneous animal collection:

    class Animal;
    class AnimalGroup
    { protected:
       Animal * animals;
      public:
       virtual void accept (Animal *ap) {...};
        ...
    };

Since it is a homogeneous collection, it should contains animals of the same  
type. The concept of "same type" is relatively dependend on what the class  
designer means. Suppose the same type" is based on the *family* according to  
the systemtic zoology. Then the collection should be of all dogs, or all cats,  
etc. We have to run time type check the input of "accept" in order to ensure a  
proper call:

    class Cat: public Animal;
    class CatGroup: public AnimalGroup
    { protected:
         // Animal * animals;
         // I wish I could narrowing the scope of "animals" to Cat here
         // but unfortuanetly I can't do that in C++. Well, I'll keep the
         // fact in my mind and assume that it has been narrowed.
       public:
         void accept (Animal *ap)
            // I wish I could narrow the scope of "ap" to Cat here,
            // but unfortunately, if I do, it will not the function that
            // will override the virtual function defined in the base, and 
            // then if someone operates on this cat group through a AnimalGroup
            // interface, it could be totally wrong! 
         {  // Okay, since we cannot present a type safe interfacewe in C++, 
            // we have to run time type check here whether *ap is the right
            // animal we should accept.
            if (typeof(*ap)==Cat) 
               // put this cat into the group according to the specific
               // orgnization of the cat family
            else 
               // we can do nothing here
         };
      };

[people may suggest using templates for this case. But I happened to be a  
person dislikes the C++-style templates, on which I have already posted my  
opinions in this news group. Specifically for this topic, using templates, you  
cannot achieve a polymorphic interface on AnimalGroup. For example, if I want  
to define a heterogeneous collection of the animal groups, how can I implement  
a general interface to access to concrete animal groups in this heter  
collection? Using temaplate again?  No. It doesn't help, since templates does  
not support heterogeneous data structure.].

What I give is only a very simple example. In practice, specialization in  
derived classes is a very commom requirement. Without run time type check,  
calling functions in derived classes through a base interface could be very  
dangerous.

Even we have run time type check, it is still not safe to code the functions in  
derived classes if I happened to forget the run-time type checking. We can pick  
up the topic of covariant specification now. only if we can specialize the  
interface in derived classes, can both calling abd coding functions in derived  
classes be free of any violation.

The concept of "thsclass" is one step close to this goal.

David Shang






Newsgroups: comp.lang.c++