We're in a curious state right now in the OO programming language arena. On the one hand, we have people who are pushing static typing further and further. On the other hand, there's a been a resurgence of interest in dynamic typing. Ruby and Python get more and more popular every day.
I don't think that these two trends are disconnected. I've run into a number of people who look at generics in Java and just say "why?" In certain domains, you want every assurance you can have. But, the conceptual overhead of what are, essentially, two completely different type schemes (parametric and subtype polymorphism) in one language is undeniable. It's like building a bridge in which all of the left-diagonal pieces are one type of metal and all of the right-diagonal pieces another. It's complicated and you end up with an incredible moiré pattern. It's rather hard for me to believe in that this is the best that we are capable of in the industry.
For me, the most interesting bits in statically typed OO programs are the places where you can use the two both forms of polymorphism to subvert static typing entirely. One of these is the boost::any class in C++.
boost::any allows you create a dynamic typing wormhole in C++. Here's how it works. boost::any is a class which holds any value object. For instance, you can create an any from a character pointer like this:
boost::any anAny("Hello There\n");
And, you can make an any from a long like this:
boost::any anotherAny(1L);
Since any is just a copy constructible value class, you can copy anys here and there:
vector<boost::any> container;
container.push_back(anAny);
container.push_back(anotherAny);
And recover the values using a cast:
long value = boost::any_cast<long> (anotherAny);
If the cast doesn't match the value in the any object a bad_any_cast exception is thrown.
The implementation of boost::any is rather tricky. It uses templated constructors and an internal "holder" template class that mixes subtype polymorphism and parametric polymorphism to allow it to vary with the type of the object it was created with. If you want to see the details, they are here in the source.
Yes, static typing can be useful, but it's nice to have an "out." The cool thing about any is that it allows you to have to tight assurance when you need it. You can't use the value of an any without casting. But, you can use it to get a bit of leverage in the moiré that would be hard to get otherwise.

Comments (4)
It seems to me that a well defined object layout such as exists in Java with the Integer and Boolean classes allows for all things to come from one base class Object which allows for the ideals of OO coding to shine through. There really seems that if you have designed your object layout with grace then you can have the flexibility of the loosely typed languages with the cleanness of the statically typed languages. There are definatly ups and downs to both but to me it feels like the static type languages are as flexible as the dynamically type languages.
Posted by CSdread | August 24, 2007 8:29 PM
Actually, boost::any isn't that useful except when used as a type-erasing tool (e.g. boost::function).
It's capability is far weaker than that of dynamic-typing. Dynamic-typing usually means that types are attached to values/objects, as opposed to static-typing where types are attached to variables. And more importantly, dynamic typing often implies that more concern is put on "what an object can do" instead of "what an object is" ( e.g. duck-typing in ruby), which is something boost::any can never provide.
For instance:
struct A
{
void draw() const;
};
struct B
{
void draw() const;
};
boost::any drawable = ...;
drawable.draw(); // no matter whether it's an A or B
This is a typical example of what we can't do in static-typed language and can in dynamic-typed language.
So to sum up, without fundamental language support, facilities like boost::any are no more than a cute type-erasing tool providing convenient but not essentially more powerful capability.
Posted by pongba | August 24, 2007 10:19 PM
Oh, and by the way, although we can put values of different types in a container of boost::any, creating an illusion of dynamic-typing:
vector container;
container.push_back(A());
container.push_back(B());
we really can't do anything about the container, because we don't know the actual type of container[i] which makes us not able to properly cast it.
In a way, boost::any is no more than a void*, with the only exception that very thin RTTI information is attached.
Posted by pongba | August 24, 2007 10:24 PM
Objective-C anyone?
Posted by mike | August 28, 2007 11:43 AM