Reflection and Introspection

Started by
26 comments, last by loufoque 14 years, 8 months ago
Hello there, I'm curious about the level of interest in reflection/introspection for C++. What I'm talking about is a system that can take an arbitrary class - without special macros, templates, or base classes, and extract metadata - class names, function names, and so on. Then you can call the functions. An example would be an XML streaming system that can look for property get/set functions in a class, or public member variables, and save-off the instance's data or load it at a later time. Or a property sheet that can take an arbitrary class instance pointer, and look for get/set functions, so as to make a class's data editable. It's the sort of thing that you might use to make tools - level editors and so on. For example, calling a function might look like this:

    MetaClassInstance c=reflection::MakeClassInstance(instance_ptr);
    MetaFunction f=c->GetFunction("GetSize");
    float size=f();
In this case, a MetaClassInstance contains a pointer to an instance, and automatic meta-data saying what kind of class it points to. A MetaFunction contains the instance pointer, and a reference to the function we asked for - if it exists. Then we call the overloaded () operator of MetaFunction, and this invokes the function, which obviously knows what class instance it refers to. So we could just say:

    float f=MakeClassInstance(instance_ptr).GetFunction("GetSize")();
- although, obviously we want exceptions or some kind of error output if the class has no function GetSize(), or it takes one or more arguments, or doesn't return something that converts to float. Would this kind of system be worthwhile to the community? Would you use it, or roll your own? Have you already rolled your own, and if so, how did you get on? And for this kind of system what would be a good syntax for the meta functions?
--------Roderick
Advertisement
Should such a system existed, my only interest would be in how it was accomplished.
People that want that kind of trouble (where the boundaries between code and data are blurred) have their own languages (like Perl, and probably many other interpreted languages). I will try very hard to keep my sanity and not work in projects that involve that type of shenanigans.

Several such projects already exist such as this or this not mention actual dialects of C++ that contain reflection such as C++/CLI.

In general, my point of view is that if I'm using C++ and need reflection, then I've chosen the wrong language for the job.
Quote:Original post by rvkennedy
Would this kind of system be worthwhile to the community? Would you use it, or roll your own? Have you already rolled your own, and if so, how did you get on? And for this kind of system what would be a good syntax for the meta functions?


A reflection/introspection system that would cover *all* cases is, for all practical purpose, impossible (template instantiation is a big problem). In addition, it would be reasonably inefficient. This is one of the reasons why reflection was never added to C++. So whichever solution one chooses, it will only support a subset.

In practice, reflection capabilities involve ability to iterate over members:
template < class T, class Visitor> void visit(Type & t, Visitor & v) {  visit(t.a, v);  visit(t.b, v);  visit(t.c, v);};


The deciding question now becomes - where does the visit function come from? It can be manually written, generated from IDL, etc...


But as far as generic library goes - it's called C# .Net.
There are ways of iterating over data members using only a template decoration for them, which has the advantage of them ending up being almost as cheap as their POD equivalents. You could *probably* extract inheritance this way, but I've never got that working.

I think it's *just about* possible to do create-classes-by-name without having to using macros to feed the classes/names into factories. But it's awfully finicky and system dependent and only just about works.

The data member names are just impossible to get at. They exist in the debugging information, but a stripped executable just *doesn't know* those names; it only knows them as offsets from the instance pointer. You have to use macros or template systems to store those names.

I'll second the viewpoint that this is the wrong language to do this stuff in. I periodically have a play with it, but it's more from gallows humour than any belief I could ever make it work properly...


Lots of interesting replies! I should perhaps have explained - I looked at the template/macro libraries early-on, but wanted to avoid something that forced any change in the class definition, or made me double-up definitions by defining something once in the main class declaration and again in a macro.

As for using the wrong language - well, I posted this in General Programming because it is general. But I write software for games - on the higher end of the hardware scale: PC, X360, PS3. And C++ is the standard there for a number of reasons. If I create a class to go in a game, I would want to write the editor in the same language, so I can re-use the class. Building tools in a different language from your engine leads to a world of pain, and as a middleware provider, I work in the language my customers use.

I perhaps should have explained as well that this isn´t a hypothetical proposal - this system already works. My question is whether I should release it for wider use or not - along with a bit of polish on the syntax and feature set.

Re. Telastyn - why would you spend your time learning how something works that you don´t want?
--------Roderick
Quote:Original post by rvkennedy
or made me double-up definitions by defining something once in the main class declaration and again in a macro.


This is impossible in C++. Unless everyone by now missed some obscure detail which makes it possible.

GCC can be made to emit enough information to just barely create serialization code, but that can hardly be considered a viable solution. It's also possible to use external tool to create the definitions, but those tend to be problematic for non-trivial examples.

Anything that is dynamically allocated is also incredibly tricky in practice without user assistance.

Quote:I perhaps should have explained as well that this isn´t a hypothetical proposal - this system already works. My question is whether I should release it for wider use or not - along with a bit of polish on the syntax and feature set.


If you managed to overcome double definition, many would be interested.
Quote:Original post by rvkennedy
Re. Telastyn - why would you spend your time learning how something works that you don´t want?


Because unless I (and others) have misunderstood you, or you misrepresented your claims, you'd've accomplished something I wrote off long ago as technically impossible (short of writing a variant compiler). I would be remiss if I didn't visit proof about something that I was patently wrong about.
Qt has also a powerful Meta-Object System.

This topic is closed to new replies.

Advertisement