From: jbn@lulea.trab.se (Johan Bengtsson)
Newsgroups: comp.lang.c++
Subject: Re: Downcasting (was: Re: run-time type checking)
Date: 21 Aug 92 11:56:42 GMT
Organization: Telia Research AB, Aurorum 6, 951 75 Lulea, Sweden
X-Newsreader: Tin 1.1 PL4

maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
: In article <4847@holden.lulea.trab.se> jbn@lulea.trab.se (Johan Bengtsson) writes:
: 
: I certainly dont have a more convincing argument
: than the example I gave before:
: 
: 	class X { 
: 	protected: 
: 		int i;
: 	public: 
: 		int get()const {return i;}
: 		X(int j) : i(j) {}
: 	};
: 
: 	class Y : public virtual X {
: 	public: 
: 		Y(int j) : X(j) {}
: 		void set(int j) { i=j;}
: 	};
: 
: 	f(X&);
: 	Y aY;
: 	f(Y);
: 
: I am disturbed by the fact that f can modify its X object when the
: interface says it cant.

****	I agree that this makes static typechecking more "loose".

	I think this looseness is needed, because it can be
	difficult to write programs that never looses significant type
	information, especially if you are using (inheriting from)
	other peoples classes.

	Cast-downs are dirty (but sometimes quick) solutions
	when you find you have lost significant type information.

: >	I think we agree on the need to sometimes do controlled downcasts.
: 	
: 	Dont know what you mean by 'sometimes'. I propose no
: downcasting, ever.

****	Fine, but note that, if you define X::operator Y* (),
	then you are in fact suppporting controlled down-casting to Y.

: 	Downcasting is an ABUSE of the concept of polymorphism,
: it tries to mix up the ideas of polymorphism with heterogeneity.
: These are totally different mechanisms conceptually that unfortunately
: both can be implemented using inheritance.

****	I note that the combination of polymorphism and heterogeneity
	weakens the restrictions on what can be done with a polymorphic
	reference.

	You have a point that a function that down-casts its arguments
	is _always_ bad.

	On the other hand, down-casting a return value is not so bad:

	void g() {
	   Base& b = findObjectUsingCommercialLibraryThatOnlyKnowsBase();
	   MyDerived& d = refcast(MyDerived,b);
	}

	In this case I "know" that I have previously stored an object
	of type "MyDerived", but this type was not known when
	the library function was written.  Templates can surely help,
	but my point is that this particular use of down-casting
	does not break polymorphism the way you describe it
	I don't think the library function should make any assumption
	about what might be done to the returned object, if it
	indeed was intended to support future inheritance.

	Also, it is likely that people will run into the situation
	where a template could have been used to avoid the need for
	a downcast, but wasn't.

: 	I see the problem is that because you can add arbitrary
: derived classes polymorphically people assume they can arbitrary
: classes heterogeneically too.

****	They can, but normally shouldn't.

: >	[...]You can't find out which
: >	derived classes override a virtual by inspecting the
: >	base class.
: 
: 	Of course not. You dont CARE how or whether the derived class
: defines the virtual. Indeed you MUSTNT KNOW. And you dont NEED to know.
: That lack of knowledge is power. Only by denying all knowledge
: can you claim arbitrariness, and only with arbitrariness do you
: have openness.

****	These are good points.

	Which brings us to the point where I jumped into this discussion:

	Declaring explicit operators for down-casting ( X::operator Y*() )
	gives the base class too much knowledge.  If you wish to
	do down-casting at all, it is more "open" to do direct
	down-casting, without the base class knowing about it.

-- 
--------------------------------------------------------------------------
| Johan Bengtsson, Telia Research AB, Aurorum 6, S-951 75 Lulea, Sweden  |
| jbn@lulea.trab.se; Voice:(+46)92075471; Fax:(+46)92075490              |
--------------------------------------------------------------------------