archives

Upward and downward polymorphism in object oriented languages.

Let's say, for the sake of argument, that I have defined a (virtual) base type 'bird' containing a pure virtual function 'sing', so every (non-virtual) derived type of bird must provide an implementation of that function.

I derive three classes, 'wren' where it results in fairly complex twittery noises, and 'crow' where it results in relatively uniform 'caw' sounds, and 'lyrebird' which selects from a long list of other birdcalls, cell phone ringtones, doorbells, chainsaws, deisel engines, etc etc etc...

I then make a list of birds. I want to iterate down that list calling 'sing' for each bird. This is an example of 'downward polymorphism' because I want members of the base class to invoke the behavior of the child class.

The same thing is true if I provide an implementation of 'sing' in the base class, which plays 4 minutes and 33 seconds of silence. When I iterate down my list of birds, where there are no virtual birds, it is no more helpful. Instead every bird is silent. This is 'upward polymorphism,' where any member of a derived class behaves as a member of its parent class, ignoring implementations of functions overridden in the derived class.

I happen to think that upward polymorphism is almost useless. What's the point of having a class whose behavior varies according to subtype if you then have to keep track of what subtype some particular instance is in order to get its correct behavior?

I wind up implementing downward polymorphism myself. This means a *variable* field in the base class containing the function pointers, an implementation (for the base class) that transfers control through that pointer, and a constructor for each derived class that writes its own function pointer into that variable (via a series of nasty binary cast operations on copies of the 'self' and function pointer which my compiler has to be beaten over the head to allow).

In other words, using OO and polymorphism in C++ almost exactly the same nasty, unsafe way I use it in C. The only advantage, from my point of view, is the ability to provide the interface and calling conventions people expect if it's ever to be integrated into the same program with various libraries. The disadvantage is that c++ compilers require more beating over the head, ignoring more warnings, etc, to be tortured into allowing it.

Why isn't there a nice, safe, compiler-supported implementation of downward polymorphism? Is it really as dangerous and bizarre as the reactions of implementors and compilers seem to imply? Is the way I'm doing it by hand really better than just providing a language construct, or even a template library, that does it automatically?

Honest to god, transferring control through a pointer isn't significant overhead.