12.24.2010

RTTI

As I said to my self before, during christmas I don't do anything that's not personal motivation. And well - waiting for presents and preparing all the glitterglammer-bimbam-jam stuff revitalized me a bit and I got into a healthy think mood that was the usual state for me before I got into this horribly work-loaded semester. And yes, I thought about extending the currently rather lousy feature set of ITK with some elements I was always interested in, but never used it due to too heavy, general overhead: Runtime Type Information (RTTI). C++ has, by default a rather annoying implementation. But to be fair, most RTTI implementation are lousy cause they span across the whole environment. Out of can interesting circumstance, I discovered that, surprisingly, wxWidgets has it's own RTTI implementation besides the C++ standard. I read a bit more about it and learned that their RTTI implementation is older than the one integrated in C++ nowadays. Some compilers still have no RTTI support, so it is quite a cool thing they did their. Only problem: it uses macros. Well, that's just bad for a toolkit like ITK which I want to code as macro-less as possible. So this fascinated me and I thought a bit here and a bit there  and it made BAM late in the night. So my own, early version of primitive RTTI was born. No, it wasn't really RTTI, but I managed to assign every class derived from a special RTTI class a unique ID with the help templates and static variables. Today I extend it far enough to support RTTI classes, objects with RTTI IDs and a cast function to cast from bases to their derivatives and derivated to their bases. There is also another cast method to cast stuff only when the object's ID matches the destination class' ID. So yes, it's effectively a fully functional RTTI implementation that doesn't require every variable to have an ID. Another cool feature, though due to the way I had to implented, is that you can add type IDs to classes but still have objects with and without RTTI ID simultaneously! I used a special wrapper class to create RTTI class objects with their IDs and a special cast function to make them compatible with each other (as long as they share the same base/inheritance branch etc). It basically maps down the C++'s internal cast verification. Quite cool that I got it done without doing so many actually ugly macro usages. In the current implementation, it's quite nice to work with I think. As I noticed that multiple inheritance doesn't work, I got a quick idea how it could work and it did. But it took me some time to realize why, tuning my brain for not less than 15 minutes to understand what weird templaty compile steps it went through. So multiple inheritance does also work, through with a different syntax than you're used for normal, non-RTTI classe. Here's how it looks it usage:

using namespace ITK::RTTI;


struct A: Class {
  void Aprint() {printf("A\n");}
};


struct B: Class {
  void Bprint() {printf("B\n");}
};


struct X: Class {
  void Xprint() {printf("X\n");}
};


struct C: Class {
  void Cprint() {printf("C\n");}
};


struct D: Class > > {
  void Dprint() {printf("D\n");}
};


int main() {
  Object a; printf("A a: %d\n",a.typeID());
  Object b; printf("B b: %d\n",b.typeID());
  Object c; printf("C c: %d\n",c.typeID());
  Object d; printf("D c: %d\n",d.typeID());
  d.Aprint();
  d.Bprint();
  d.Cprint();
  d.Dprint();
  d.Xprint();
  Object* q = d.cast();
  if(q->typeID()==D::staticID()) printf("q points to an object of type D\n");
  if(a.typeID()==b.typeID()) printf("types A and B are equal, holy crap!\n");
  return 0;
}

Another surprising detail is that you can just create Object<> objects (these are objects with an RTTI ID) with non-RTTI classes. The system does completely base on templates, static members and class inheritance. So it's just a header you need to include and you can select where and on which objects you want to use and where not. And as you can see in class D, that's the way you can create multiple inheritance, but simply nesting a special, empty template class. The solution is so simple in execution but rather complex to explain in theory, I'm afraid to write the documentation for it. Well, atleast it's easy to explain how to use it. I'm happy it works. Maybe I can take now a look at more intelligent pointer structures, automatic memory address resetting etc. Some things floating in my head and popular among garbage-collected languages. One of my goals is have useful features, but only selective and not destroying the performance for code that doesn't need it. A blend of features from bytecode languages and strongly OOP-e-fied systems.

Oh, and you can of course cast down the RTTI object to it's original RTTI class while not caring about it's object ID. So as far as I can image, you can get the right objects you want in any case. Of course, handling RTTI objects and non-RTTI objects requires you differentiate their usage if you still want to access the type ID. But there's no way around it (not even in concept), they are simply two different classes, one with and one without type ID. But still, the compiler supports me to suppress backdoors he also suppresses for it's own system. Hooray for templates and inheritance!

No comments: