|The Classy Cast|
|Written by Mike James|
|Friday, 26 November 2010|
Page 2 of 2
This is an example of pragmatic static typing meeting a situation that really calls for dynamic typing. The point is that a myClassB isn't really an instance of a myClassA object in any proper sense. The only way it can be cast to a myClassA object is by an active type converting cast. The only safe casts are passive and simply allow a sub-type to be regarded as a base type with no active conversion needed.
The problem becomes clear as soon as you see the code for the explicit cast operator:
class myClassB : myBaseClass
It can only work by really doing the conversion on the myClassB object into a new myClassA object.
This is fine as long as you are not expecting any changes to the newly generated object to be passed back in some way to the original. That is it b is the property on the new temporary myClassA object then
will work but
obj.b = 0;
changes the b property on the myClassA temporary object which is deleted as soon as the method ends.
There are so many ways to avoid this problem that it is difficult to know where to start or which point of view to emphasise. It is clear that our fundamental problem is poor inheritance hierarchy which encourages programmers to try and fix it. Perhaps a better and more fundamental approach would have been to take a dynamic point of view and write the method that works with myClassA as:
void myMethod(dynamic obj)
In this case there is no need to use a cast to call it with myClassB or indeed any class. The only requirement for this to work is that the instance passed as obj has a b property.
This works but if you want to avoid runtime errors you have to add safeguards against using non-existent properties and methods.
If you want to stay with static typing then you need to stick to the rule that you do not write custom active type converting casts. If you need an active type conversion e.g. a myClassB into a myClassA then write a type conversion constructor:
class myClassA : myBaseClass
Now the only way to "cast" the myClassB object is to use the conversion constructor:
myClassB myobject = new myClassB()
and it become immediately obvious that a new object is involved in the conversion. This doesn't exactly solve the problem but it does make it clear to see.
There are almost certainly other approaches to the difficulty and many programmers who would say that you shouldn't ever get into this position by creating an inheritance hierarchy of this sort. There are also programmers who would hold that inheritance hierarchies are a waste of time and if a myClassB object can behave like a myClassA object then let it.
The one clear message is: don't create active type conversion casts unless you really have a very good reason to do so.
|Last Updated ( Friday, 07 January 2011 )|