From: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Subject: Re: downcasting (was Re: GOTOo wars)
Organization: MAXTAL P/L C/- University Computing Centre, Sydney
Date: Sun, 4 Oct 1992 11:41:45 GMT

In article <1992Oct2.141636.17829@jyu.fi> sakkinen@jyu.fi (Markku Sakkinen) writes:
>In article <361@ulogic.UUCP> hartman@ulogic.UUCP (Richard M. Hartman) writes:
>>In article <9227521.28722@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON) writes:
>>>hartman@ulogic.UUCP (Richard M. Hartman) writes:
>>>
>>>>We're using the NIH Linked List.  When you get something off
>>>>the list it is just an Object *.  To actually use it you have
>>>>to downcast it to it's proper (and hopefully Object-derived :)
>>>>class.  If someone knows a way around this, please let me know
>>>>and I will *gladly* give up my use of castdown......
>>>
>>>The Politically Correct way of doing this, I believe, is to use a template
>>>linked list class. (Look Ma, no casts! :-)
>>
>>That only works if you compiler supports templates.....	:(
>
>And templates only help in defining homogeneous container classes.
>If you really need a heterogeneous list, it's hard to avoid castdowns.
>

	I cant agree with this.

	For a start, you cant have a heterogenous list or array.
The only proper mechanism that supports multiple different objects in C++
that I'm aware of is 'struct'.

	Now suppose we want to have a list of pointers to objects
which might be type A, B or C. But this is impossible. 
We must have a list of a single type T. So we must UNIFY A*, B* and
C* thus:

	union T {A* a; B* b; C* c;};

Now it makes sense to have a list of T. The list is homogenous,
it contains elements of the same type. This mechanism is sound,
it breaks no rules about soundness. It is not safe, however.
It can be made safer using a discriminant if the ordering
of the objects is indeterminate, and as completely safe
as anything else in C++ by using a language controlled
tagged pointer mechanism.

	typedef [A,B,C] *T; // tagged pointer type T

	There is a second type of list one might consider.
This list consists of pointers to objects derived from Base.
Here, polymorphism/inheritance unifies the type: it homogenises
the type. A list of pointers to Base is homogenous, not
heteromorphic. After all, all the pointers point to a Base,
and every object derived from a Base 'isA' Base (or should be
to be used in this type of list).

	This second type of list has the added advantage
of allowing INDETERMINATE objects derived from base to
be pointed to, at the expense of restricting you
to interfacing via the Base. (Often facilitated by
virtual functions).

	In both cases we want sound practice, namely, to access
the list elements by the declared interface only. 

	The two mechanism can be combined, assuming
D1, D2, D3 are derived from Base we can have:

	typdef [Base,D1,D2,D3] *T;

and use the Base* for polymorphic calls and the D1, D2 and D3 
pointers for heteromorphic ones.

	The trade off between the two mechanisms is simple:
Type 1 (union) allows selection of a known, finite, predeclared
number of interfaces, whereas Type 2 (polymorphism) allows
a single fixed interface to an arbitrary number of derived
types. They can be combined.

	Downcasting is not required by either of these mechanisms.
This mechanism should suffice in almost all cases where you 
think you need a heterogenous list.

	Downcasting does offer something neither the above 
mechanisms does, and for that reason I am suspicious of it.
It allows an arbitrarily chosen but finite set of classes
to be checked for, *as if* they had been declared
like a tagged pointer, at one local place in the program.
However at another place, another different set can be
chosen. Therefore, since the number of such places
in a program is unbounded, the number of derived classes
that are special is *UNBOUNDED*.

	Now polymorphism already manages an unbounded (arbitrary)
number of derived classes by homogenising the interfaces
(that is, by virtual functions). That such restrictions
are required to have polymorphism operate properly
in a system built of closed modules seems to indicate to
me that downcasting perverts the course of type safety.

	I want to consider what happens in a system
with dynamic linkage. This can just be dynamic class loading,
or it can be cooperating processes, an DBMS server,
an embedded system, etc. All those things not
"domestic". 

In C++, the system is broken down into the compilation and linkage stages.
Although the compiler cannot know about all the classes, the linker
can, so with suitable cooperation RTTI can be provided to allow
safe downcasting to operate. In particular, access to the
complete system inheritance DAG is required.

Now consider an upgraded system like Windows that supports
dynamic linkage. In this case there is a third 'link'
stage when a module is dynamically loaded, and at this point
we require the complete system inheritance DAG to be
accessible, so, the previou partial DAGs built by the
static linker must be merged by the dynamic linker.

Can you imagine this happening over distributed processes?

Yet without downcasting, the dynamic linker need only
perform much the same job as the static linker does now.
Without RTTI, the problems of merging the RTTI on
dynamic linkage cannot arise :-)

The fact that it does seem to indicate to me that downcasting
is unsound. It introduces additional, undeclared, coupling,
and that coupling has a precise form, namely the RTTI.

Except for exceptions (pardon) C++ has almost no run time system,
and the run-time system it does have is 'new/delete'. This is nice.

Incidently, what happens to an object I 'throw' from a dynamically
linked module called from another? How does the caller
catch it, if it is say a derived object of a type
unknown to the caller, but there is a 'catch' for the base class?

The answer to this must be exception specifications.
And they are a finite list of things that can be thrown.
Across dynamic linkage boundaries the rule that you
*should* only throw objects listed in the exception
specifcation might just have to be upgraded to
*must* if the system is to function.

Any comments?

-- 
;----------------------------------------------------------------------
        JOHN (MAX) SKALLER,         maxtal@extro.ucc.su.oz.au
	Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Newsgroups: comp.lang.c++