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: Mon, 27 Jul 92 16:14:41 GMT

> shang@corp.mot.com (David (Lujun) Shang) writes:
> 
> >Now I give you an example that truely needs multiple dispatch.
> >
> >class Animal
> >{  Animal * fight (Animal * a)
>     // simplified version for brevity
>     {  return this->strength() > a->strength ? this : a; }
> >};
> >
> >and we have the following fights:
> >
> >Animal * victor;
> >..
> >victor = wolf.fight (jackal);
> >victor = lynx.fight (victor);
> >victor = bull.fight (victor);
> >..
> >.....

In article <9220719.894@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus James  
HENDERSON) replies:

> I don't quite understand you example.
> It seems to be incomplete.
> Presumeably after all the fights, you are going to do something like
> 
> 	if (typeof(victor) == typeof(wolf))
> 		cout << "The wolf won!\n";
> 	else if (typeof(victor) == typeof(lynx))
> 		cout << "The lynx won!\n";
> 	else ...
> 
> To me that looks like horrible design.
> Why not just have
> 
> 	cout << "The " << victor->name() << " won!\n"; 
> 
> instead? Then there is no need for downcasting (and you also have a better
> design!).

Sorry that I did not complete my program, which caused confusion. I'm going to  
write something like:

        count << victor->name() << ", the " << type_name(typeof(*victor))
              << " won!\n";

[note that from the animal name, you may not know what kind of the animal is] 
the result may be:

        Pooh, the bear won!

or, I may write:

        bestow_on (victor).

where bestow_on is a function which gives a female peer to the victor (suppose  
only the male can fight):

       void bestow_on (Animal * victor)
       {    Animal * f = new typeof(*victor)(female));
            // suppose we need do some work for the female here
            // ...
            victor->mate(f); // type inference here ensure that f is the 
                             // correct type and the downcast is safe
       };

here both RTTI and downcast are needed, though I did not write an explicit  
downcast which is actually happen in the call of "mate":

        victor->mate( (typeof(victor)) f);

since the interface of mate specifies the input of animal must be the same type  
of animal as the victor [see my previous poster]:

       void Animal::mate (thisclass *);

The downcast is performed implicitly and checked by the compiler to ensure each  
downcast is CORRECT and SAFE at run time. For example, if write:

       Animal * f = new bear;
       dog->mate(f);

The compiler won't let you pass the above program because when you call  
dog->mate(f), f is the type of bear. The (implicit) downcast cannot be  
performed. The compiler won't let you pass either if it cannot infer whether it  
is the correct type, in this case, the programmer must present an explicit  
run-time type check to ensuure the correct downcast:

      if (typeof(*f)==Dog) dog->mate(f); 

However, if you write an explicit downcast here:

       dog->mate((Dog*) f);

that means you are deliberately to break the type system. The compiler will  
give you a warning when it either knows the downcast is not correct or does not  
know whether it is correct.

I wonder if you can figure out a better design that needs not RTTI and downcast  
for "bestow_on" and "mate". Downcast may not needed if you provide your own  
virtual function for the type id, say "Species()" as suggested by John. But I  
don't think it is a better design because it is not safe for the first two of  
following three reasons and not efficeint for the last reason:

(1) You must remember to override the virtual function. If you forget, errors  
happen. The compiler has no way the essure a correct type id distribution.

(2) You must remember to run-time check of the type id. The compiler has no way  
to help you to enssure the correct match. If you forget to check, you produce  
the error.

(3) You let down the run time performance since you have much work of type  
checking that can be done at compile time done at run time.

Downcast is not safe only when the compiler can not ensure that the downcast  
will not produce a cast between two different types. With language supported  
RTTI, all language supported automatic downcast will be deadly safe.
 
David Shang
Newsgroups: comp.lang.c++