How the fate like to play with us (3rd generation of RTTI)
Life bring to us surprises everyday but today I was impressed how fate works.
Whole story started few years ago when I decided to make my own RTTI system for White Rabbit Engine. Then I was still young and naive and thought like everybody at this age that I know how to write complicated systems. This experience teach me that I really can write complicate systems ... but not necessarily should. System was working fine but was over complicated and resulted in lot of stability issues.
This realization lead to the series of improvement. I like to call it 2nd generation of RTTI system. Changes are covered by on of my posts. This was already big step: system was simpler, easier and what most important more stable. This sentence could probably end this story if not the fact that I always felt that it is still not final form of this piece of code. This wasn't what I fully wanted.
There was one particular feature that I struggled to add but failed to achieve: virtual members.
Concept was simple. In RTTI v2 declaration of members look like that:
RTTI_DECLARATION_BEGIN(CMyRttiClass) RTTI_ATTRIB(m_name) .setAlias("Name") .setEditorParams("[Unique]"); RTTI_ATTRIB(m_meshResource) .setAlias("Mesh Resource") .bindSetCallback(&CMyRttiClass ::setResource) .setEditorParams("[Ext:'msh','mshxml']"); RTTI_DECLARATION_END
And I wanted to do something like this:
RTTI_DECLARATION_BEGIN(CMyRttiClass) RTTI_ATTRIB(m_name) .setAlias("Name") .setEditorParams("[Unique]");RTTI_ATTRIB(m_meshResource) .setAlias("Mesh Resource") .bindSetCallback(&CMyRttiClass ::setResource) .setEditorParams("[Ext:'msh','mshxml']");RTTI_ATTRIB(VirtualMemberOfClass) .setAlias("VirtualMember") .setSerializers(WriteVirtualMember, ReadVirtualMember); RTTI_DECLARATION_END
VirtualMember is variable that don't exist in CMyRttiClass but you can specify custom reader/writer and everything will works like it is a member of the class. I tried to add it for some time but there were some many issues and edge cases that I gave up because of time constrains.
Now we are three years later and I already using 3rd generation of my RTTI system which looks like that:
RTTI_DECLARATION_BEGIN(CMyRttiClass) RTTI_ATTRIB(m_name) .setDefaultSerialization<CStringID>(); RTTI_ATTRIB(m_meshResource) .setDefaultSerialization<CMeshResource::Handle>(); RTTI_DECLARATION_END
I drop all the edition information from code and moved it to special definition file. Its describe how to display class in inspector. Example of class definition bellow:
def("CMyRttiClass")Advantages of this solution is:
"m_name" : CStringID <"Alias": "Name">;
"m_meshResource" : FilePath < "Alias": "Mesh Resource", "Filter":"#meshes#" >;
- Thanks to hot reloading I can change this filein run time
- It created separation between code and edition (I going more and more into this direction).
- Whole change simplified my RTTI code.
- I need to manually modify this script when I modify code.
- I needed to create pretty extensive validation and bug reporting for whole system.
RTTI v3 is in use for some time already and I'm somehow surprised how solid this concept hold. Only thing that I didn't expect from this change is that it will made virtual members concept possible. I can say even more it was pretty trivial to do.
That is why I mentioned that fate like to play with us. When I wanted to add virtual members I couldn't but when I stopped trying it just happened. Of course this is simplification and in practice this it result of all this years of changes. In the end don't think that this feature would be possible to achieve in other way.
Normally I probably wouldn't able to see how much I grow as a developer over the years but I'm one of this few who still work on the same code base after years. This allow me to see where I am, where I was and how naive I was when I was starting this project. Now I'm one step closer to its epic final...