Checking interest: reflectable types

In my work I've developed a sort of reflection library for C++. There are still many problems to solve before it could near real reflection but I don't believe they are insoluble. It works much like fusion maps except that you can extend them through inheritance. In fact, my current implementation uses fusion to do its thing and with some minor changes to fusion::map it could provide the base. There is a boost.reflection proposal out there that is meant to work with boost.extension. This one is a bit different in that you're not additionally defining data; instead you declare your reflection as you declare your reflectable type through the instantiation of and inheritance from template metafunctions. It's primarily a static/compile-time kind of reflection but can be extended into runtime simply by making your field types a little smarter. Fields describe the data and provide access identifiers. Since they are general types that simply have to have an internal typedef you can attach whatever information is useful. We've done such things as attach valid value ranges, labels, etc... I currently use it do auto-construct property trees for user editing. I plan to use it for scripting/extension. I've had a look at boost.python and it looks like it would be possible, without too much difficulty, to automate python exposure of these types. A coworker with 0 experience in metaprogramming found it fairly easy to feed the types into a structure meant for a report design and printing library. This isn't a promise to actually do anything. I'm just gauging how much, if any interest there is to decide if I want to go to the trouble of hobby developing a publicly available and usable version.

On Wed, Apr 27, 2011 at 6:41 PM, Noah Roberts <roberts.noah@gmail.com> wrote:
In my work I've developed a sort of reflection library for C++. There are still many problems to solve before it could near real reflection but I don't believe they are insoluble. It works much like fusion maps except that you can extend them through inheritance. In fact, my current implementation uses fusion to do its thing and with some minor changes to fusion::map it could provide the base.
There is a boost.reflection proposal out there that is meant to work with boost.extension. This one is a bit different in that you're not additionally defining data; instead you declare your reflection as you declare your reflectable type through the instantiation of and inheritance from template metafunctions.
There is also the Mirror reflection library which I plan to submit for review once it is ready. The project homepage (with links to docs and download page) is located here http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/ [snip/] Best regards Matus

On 4/27/2011 10:42 AM, Matus Chochlik wrote:
On Wed, Apr 27, 2011 at 6:41 PM, Noah Roberts<roberts.noah@gmail.com> wrote:
There is a boost.reflection proposal out there that is meant to work with boost.extension. This one is a bit different in that you're not additionally defining data; instead you declare your reflection as you declare your reflectable type through the instantiation of and inheritance from template metafunctions.
There is also the Mirror reflection library which I plan to submit for review once it is ready.
The project homepage (with links to docs and download page) is located here http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/
Yeah, the original worked like that. We found the manual registration process ungainly. Also didn't do proper inheritance...which maybe yours does. Had trouble looking at the docs and seeing how to use it since the part that probably does all the work (classes.h) isn't linked in with the examples. Use of mine is more like so: struct field0 { typedef int value_type; }; struct field1...2 ... struct my_reflected_type : build_class < var< field0, rw > , var< field1, r > // can't assign through reflection. >::type { virtual ~my_reflected_type(){} DECLARE_PARAM_CONSTRUCTOR(my_reflected_type); }; struct my_reflected_type2 : derive_from < my_reflected_type , var< field2, rw > >::type { my_reflected_type2() : type(( field0() <= some_val , field1() <= some_val , field2() <= some_val )) { // directly access read-only value and assign... var<field1,r>::value = 66.; } }; I also have a ref<> so bases can have fields to abstract types. So far functions haven't been needed here so there's none but I think I have a handle on how that could be done. All of the above can be treated as a fusion sequence and/or fusion associative sequence (including the param list). Building records on the fly with field()<=value syntax was very desired. Comes in handy when you have a function expecting a record with x,y,z fields in it, have those values, but don't want to build the record class.

On 04/27/11 13:53, Noah Roberts wrote:
On 4/27/2011 10:42 AM, Matus Chochlik wrote: [snip]
There is also the Mirror reflection library which I plan to submit for review once it is ready.
The project homepage (with links to docs and download page) is located here http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/
Yeah, the original worked like that. We found the manual registration process ungainly. Also didn't do proper inheritance...which maybe yours does. Had trouble looking at the docs and seeing how to use it since the part that probably does all the work (classes.h) isn't linked in with the examples. Hi, Noah,
Sounds interesting. I'd be interested in seeing the code.
Use of mine is more like so:
struct field0 { typedef int value_type; }; struct field1...2 ...
struct my_reflected_type : build_class < var< field0, rw > , var< field1, r > // can't assign through reflection.
Why not: var< field > , var< field const> instead? I guess I'd have to see the code to really understand why the extra type parameter is needed, but maybe a short explanation would be enough.
>::type { virtual ~my_reflected_type(){} DECLARE_PARAM_CONSTRUCTOR(my_reflected_type);
Could you provide the source code for: DECLARE_PARAM_CONSTRUCTOR to give us some idea of what it's doing?
};
struct my_reflected_type2 : derive_from < my_reflected_type , var< field2, rw > >::type { my_reflected_type2() : type(( field0() <= some_val , field1() <= some_val , field2() <= some_val )) { // directly access read-only value and assign... var<field1,r>::value = 66.; } };
Hmm... does the user have to repeat this some number of times, same the number of fields in the my_reflected_type? IOW, for I=3...N (where N is number of fields in my_reflected_type): my_reflected_typeI { //repeat like my_reflected_type2 }; Or is this done by the macro using boost,preprocessor library? I would guess the latter because providing all this boilerplate code would seem too much to me.
I also have a ref<> so bases can have fields to abstract types.
So far functions haven't been needed here so there's none but I think I have a handle on how that could be done.
All of the above can be treated as a fusion sequence and/or fusion associative sequence (including the param list).
Building records on the fly with field()<=value syntax was very desired. Comes in handy when you have a function expecting a record with x,y,z fields in it, have those values, but don't want to build the record class.
I don't understand that. Could you be more concrete in describing this use case, maybe by providing a concrete example? ---------------------------- BTW, a previous post of your's to the users list: http://thread.gmane.org/gmane.comp.lib.boost.user/66818/focus=67038 seems related to your: field()<=value syntax. Is it? -regards, Larry

On 4/27/2011 1:06 PM, Larry Evans wrote:
Use of mine is more like so:
struct field0 { typedef int value_type; }; struct field1...2 ...
struct my_reflected_type : build_class < var< field0, rw> , var< field1, r> // can't assign through reflection.
Why not:
var< field> , var< field const>
instead? I guess I'd have to see the code to really understand why the extra type parameter is needed, but maybe a short explanation would be enough.
I suppose that'd be an interesting method of doing it. The field itself though isn't the type stored so the const would have to be applied to that value or applied in the same way I end up using the access rights. Currently though in a reflected type containing a read-only field the value itself isn't actually read only. It may be that the class itself may implement other behavior that changes the value. It just means that the value is read only through the reflection API. Thus when I say "get<field>(object)" I get a const reference if the field is non-writable or object is const. If, on the other hand, I violate the API through casting (which is more normal from inside the class) I can write to that value from a non-const member.
>::type { virtual ~my_reflected_type(){} DECLARE_PARAM_CONSTRUCTOR(my_reflected_type);
Could you provide the source code for:
DECLARE_PARAM_CONSTRUCTOR
to give us some idea of what it's doing?
template < typename Params > name (Params const& params) : type(params) {} It just saves time. The type you inherit from (which declares itself as type inside itself like a lot of meta-objects) has two constructors. One is the default, the other is just like the above and forwards the params to the value implementation objects to either accept or discard. A lot of times you won't care to make one of these yourself, but instead make a constructor that uses params to initialize. It's currently important for base classes though so derived classes can forward params. Doing correct base construction is one of the to-be-solved things.
};
struct my_reflected_type2 : derive_from < my_reflected_type , var< field2, rw> >::type { my_reflected_type2() : type(( field0()<= some_val , field1()<= some_val , field2()<= some_val )) { // directly access read-only value and assign... var<field1,r>::value = 66.; } };
Hmm... does the user have to repeat this some number of times, same the number of fields in the my_reflected_type? IOW, for I=3...N (where N is number of fields in my_reflected_type):
my_reflected_typeI { //repeat like my_reflected_type2 };
Or is this done by the macro using boost,preprocessor library? I would guess the latter because providing all this boilerplate code would seem too much to me.
You can initialize or not initialize any field you chose, thus named params rather than construction like tuple<> or others. If you initialize with a set of params, the values they target will be thus initialized while those you don't supply will be default constructed. (so yeah, sort of has to do with my earlier question) If your value can't be default constructed you HAVE to provide a param for it. It then has to be copy constructable for the param will first initialize the value from your provided data. The type that feeds into a set of params is specifically the value of the field in other words (though I'm sure this could be changed, thinking of it now). If your value is default constructible it need not be copy constructible. If it is not, it'll have to be initialized to some reasonable value outside the API and you won't be able to assign to it through reflection. The current state doesn't do functions though I have ideas there. We're currently calling them "records".
I also have a ref<> so bases can have fields to abstract types.
So far functions haven't been needed here so there's none but I think I have a handle on how that could be done.
All of the above can be treated as a fusion sequence and/or fusion associative sequence (including the param list).
Building records on the fly with field()<=value syntax was very desired. Comes in handy when you have a function expecting a record with x,y,z fields in it, have those values, but don't want to build the record class.
I don't understand that. Could you be more concrete in describing this use case, maybe by providing a concrete example?
So for instance: template < typename Record > void fun(Record const& rec) { static_assert(has_field<Record, what_i_need>::value, "Supplied record doesn't have the necessary data!"); ..... } I can call this function like so: what_i_need::value_type value; int something_else; fun(( what_i_need() <= value , int_field() <= something_else)); Records and param lists being nearly interchangeable in this regard. Only showing the int_field() because it can happen...the function simply ignores what it doesn't know about.
---------------------------- BTW, a previous post of your's to the users list:
http://thread.gmane.org/gmane.comp.lib.boost.user/66818/focus=67038
seems related to your:
field()<=value
syntax. Is it?
Sort of. It's more about initializing the values themselves with the params. I ended up with something more like: template < typename Params > value_impl(Params & p, typename boost::enable_if< has_field<Params,my_field> >::type * = 0) : value(get<my_field>(p)) {} template < typename Params > value_impl(Params & p, typename boost::disable_if< has_field<Params,my_field> >::type * = 0) : value() {} I don't have rights to the code though I do the idea. If I did it I'd need to address a few things: * correct base initialization. With reflected types though your "base" is not your direct, actual base so that becomes an issue. * Better implementation of fields represented by abstract types. Currently there's three approaches: 1) have the field in the base and make it refer to the abstract type. 2) have the field in the derived and make it refer to the most derived type. Of course now you don't have access to it from the base. 3) Put one field in the base and a different field in the derived. Make the base's a "reference" field. Does the trick but it's hacky. I really want the best of both worlds. Put the field in the base to the abstract type. When I request the field from a derived record have it return the derived type. In other words: struct base_field_type; struct derived_field_type; struct field { typedef base_field_type value_type; }; derived d; base * b = &d; decltype(get<field>(d)) == derived_field_type& decltype(get<field>(*b)) == base_field_type& * functions. I imagine something like so: struct reflected : build_class < fun<fieldx, void(int)> >::type { void call(fieldx, int) { .... } }; reflected r; call<fieldx>(r, 42); // maybe call<fieldx>(r)(42); I'm not sure how much actual value this has though. Personally I don't have much use for it. On the other hand, I do have use for "fields" implemented by functions such that: int x = get<fieldx>(r); is actually a call to a function rather than reference to a variable in r.

On 04/27/11 18:23, Noah Roberts wrote:
On 4/27/2011 1:06 PM, Larry Evans wrote:
Use of mine is more like so:
struct field0 { typedef int value_type; }; struct field1...2 ...
struct my_reflected_type : build_class < var< field0, rw> , var< field1, r> // can't assign through reflection.
Why not:
var< field> , var< field const>
instead? I guess I'd have to see the code to really understand why the extra type parameter is needed, but maybe a short explanation would be enough.
I suppose that'd be an interesting method of doing it. The field itself though isn't the type stored so the const would have to be applied to that value or applied in the same way I end up using the access rights.
I did understand that a fieldI was not what was actually stored and that, instead, a FieldI::value_type was stored. The only reason for using "FieldI const" instead of "FieldI,r" as the template arguments to var was just to eliminate the need for more "type flags", such as r and rw. However, now that I've thought about it some more, that seems a minor point. [snip]
>::type { virtual ~my_reflected_type(){} DECLARE_PARAM_CONSTRUCTOR(my_reflected_type);
Could you provide the source code for:
DECLARE_PARAM_CONSTRUCTOR
to give us some idea of what it's doing?
template < typename Params > name (Params const& params) : type(params) {}
It just saves time. The type you inherit from (which declares itself as type inside itself like a lot of meta-objects) has two constructors. One is the default, the other is just like the above and forwards the params to the value implementation objects to either accept or discard. A lot of times you won't care to make one of these yourself, but instead make a constructor that uses params to initialize. It's currently important for base classes though so derived classes can forward params.
So, params is bassed to each FieldI type and that FieldI type decides which of the params to use to initialize it's FieldI::value_type? IOW, params has to contains all the information needed to initialize all type types in: base_class < var< field0, rwFlag0> , var< field1, rwFlag1> , var< field2, rwFlag2> ... , var< fieldN, rwFlagN>
and somehow, the var or fieldI classes figure how to intialize from the single params argument? Some actual prototype code would help me understand better.
Doing correct base construction is one of the to-be-solved things.
Ah, so maybe I should wait for that to have my last question answered?
};
struct my_reflected_type2 : derive_from < my_reflected_type , var< field2, rw> >::type { my_reflected_type2() : type(( field0()<= some_val , field1()<= some_val , field2()<= some_val )) { // directly access read-only value and assign... var<field1,r>::value = 66.; } };
Hmm... does the user have to repeat this some number of times, same the number of fields in the my_reflected_type? IOW, for I=3...N (where N is number of fields in my_reflected_type):
my_reflected_typeI { //repeat like my_reflected_type2 };
Or is this done by the macro using boost,preprocessor library? I would guess the latter because providing all this boilerplate code would seem too much to me.
My apologies. I should have read closer the code you provided. Apparently, my_reflected_type2 is an extension of my_reflected_type because it uses template, derive_from<my_reflected_type,...>. So, I guess the base_class<V0,V1,V2,...>::type does an mpl::fold of derive_from?
You can initialize or not initialize any field you chose,
Understandable.
thus named params rather than construction like tuple<> or others.
I don't understand "thus named params". Could you clarify?
If you initialize with a set of params, the values they target will
How are "values targeted"? I guess that's done with the <= operator you mention further down; however, that appears to use separate values for each field; yet, params seems to be used to intialize each field. Again, prototype code might clear things up.
be thus initialized while those you don't supply will be default constructed. (so yeah, sort of has to do with my earlier question)
Did you have a chance to took at the code linked-to in my reply: http://article.gmane.org/gmane.comp.lib.boost.user/67038 to your earlier question? That link to was a test driver, whose relevant part was started with: trace_scope ts("all_of_aligned index_component DEMO"); The implementation tested in that part is here: http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/composite_st... AFAICT, that code does what you describe, but with variadic templates. Briefly, it does this starting from the variadic CTOR: template < index_type... Keys , typename... CtorTypes > indexed_ctor_args_all_of_aligned ( index_component < index_type , Keys , CtorTypes >const&... ctor_args ) { args_ftor < index_component < index_type , Keys , CtorTypes >... > f_args ( this->address() , ctor_args... ) ; mpl::for_each<typename layout_indices::indices>(f_args); } The ctor_args are produced (as shown in the driver) with arguments created with: index<IndexType,IndexValue>::operator=<Component> defined here: http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/composite_st... I'd guess this index<,>::operator= plays a role similar to your <= operator. The args_ftor::get_our is used with SFINAE and args_ftor::inject to select whether to default construct the component or copy construct the component. This is done by first passing 'this' to the overloaded get_our in method: template < index_base IndexValue > void operator() ( mpl::integral_c<index_base,IndexValue> a_index )const Since '*this' is derived from all of: index_component<index_type,Keys,CtorTypes>... either the selected component is found by the compiler and: template <... > void inject ( index_component<index_type,Key,CtorType>const* a_arg )const is called and the Component copy ctor is used to inject into the components buffer, or the component is not found and: template <... > void inject ( not_in_args* )const is called and the default ctor is used to inject into the components buffer. In each case the components buffer is populated using placement new. This components buffer together with placement new allows separation of reserving the memory for the components from the initialization of components. BTW, I think (although I've not tried at all to do this with fusion) that by separating the component storage reservation from the component initialization, accomplishing this:
Doing correct base construction
would be a bit easier than with something like fusion which, since it uses member variables, must do the storage allocation at about the same time, i.e. in the same class, as the initialization. That's one reason I'm interested in seeing how you will do this (which, according to the completion of the above quote:
Doing correct base construction is one of the to-be-solved things.
has not yet been done.). Also, I'd think a non-variadic version could be done without much trouble, in case you've no access to a variadic templates compiler.
If your value can't be default constructed you HAVE to provide a param for it. It then has to be copy constructable for the param will first initialize the value from your provided data. The type that feeds into a set of params is specifically the value of the field in other words (though I'm sure this could be changed, thinking of it now).
Noah, I'm still not sure of the meaning of: the param will first initialize the value from your provided data because I thought param was the provided data. Also, I'm unsure of the meaning of: The type that feeds into a set of params Could you please clarify? [snip]
Building records on the fly with field()<=value syntax was very desired. Comes in handy when you have a function expecting a record with x,y,z fields in it, have those values, but don't want to build the record class.
I don't understand that. Could you be more concrete in describing this use case, maybe by providing a concrete example?
So for instance:
template < typename Record > void fun(Record const& rec) { static_assert(has_field<Record, what_i_need>::value, "Supplied record doesn't have the necessary data!");
..... }
I can call this function like so:
what_i_need::value_type value; int something_else;
fun(( what_i_need() <= value , int_field() <= something_else));
Ah, now I see. This expression: ( what_i_need() <= value , int_field() <= something_else ) is an example of "Building records on the fly". I'm guessing you're doing something like what proto does with expression template where you define an operator <= to produce 1 element in something like a map and then use the comma operator to augment that map.
Records and param lists being nearly interchangeable in this regard.
So, the above expression which I copied from your code is what you mean by a "param list"?
Only showing the int_field() because it can happen...the function simply ignores what it doesn't know about.
---------------------------- BTW, a previous post of your's to the users list:
http://thread.gmane.org/gmane.comp.lib.boost.user/66818/focus=67038
seems related to your:
field()<=value
syntax. Is it?
Sort of. It's more about initializing the values themselves with the params. I ended up with something more like:
template < typename Params > value_impl(Params & p, typename boost::enable_if< has_field<Params,my_field> >::type * = 0) : value(get<my_field>(p)) {}
template < typename Params > value_impl(Params & p, typename boost::disable_if< has_field<Params,my_field> >::type * = 0) : value() {}
OK, now things are getting clearer. The has_field in the above corresponds roughly to the get_our mentioned above. The Params corresponds to the superclasses of args_ftor. the value(get<my_field>(p)) corresponds to: void inject ( index_component<index_type,Key,CtorType>const* a_arg )const and the value() corresponds to: void inject ( not_in_args* )const Just above, you say:
I ended up with something more like:
However, earlier you say:
Doing correct base construction is one of the to-be-solved things.
so, is this value_impl code not yet working, or do you mean something else is not working when you say "base construction is one of the to-be-solved things"?
I don't have rights to the code though I do the idea. If I did it I'd need to address a few things:
* correct base initialization. With reflected types though your "base" is not your direct, actual base so that becomes an issue.
* Better implementation of fields represented by abstract types.
Currently there's three approaches: 1) have the field in the base and make it refer to the abstract type.
Do you mean the field is a pointer or reference to an abstract type?
2) have the field in the derived and make it refer to the most derived type. Of course now you don't have access to it from the base.
Could you use CRTP? http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern I think spirit uses this a lot.
3) Put one field in the base and a different field in the derived. Make the base's a "reference" field. Does the trick but it's hacky.
Hmmm. So 1) actually has a pointer, and the derived CTOR uses new to create the pointer which it then passes to the base CTOR? And so 3) actually has a field whose reference is passed to the CTOR of the base?
I really want the best of both worlds. Put the field in the base to the abstract type. When I request the field from a derived record have it return the derived type. In other words:
struct base_field_type; struct derived_field_type;
struct field { typedef base_field_type value_type; };
derived d; base * b = &d;
decltype(get<field>(d)) == derived_field_type& decltype(get<field>(*b)) == base_field_type&
* functions. I imagine something like so:
struct reflected : build_class < fun<fieldx, void(int)> >::type { void call(fieldx, int) { .... } };
reflected r; call<fieldx>(r, 42); // maybe call<fieldx>(r)(42);
I'm not sure how much actual value this has though. Personally I don't have much use for it. On the other hand, I do have use for "fields" implemented by functions such that:
int x = get<fieldx>(r);
is actually a call to a function rather than reference to a variable in r.
Ok, then that's beyond what the code I proposed is capable of, AFAICT. So, as I said, I'd be interested in seeing how you do this. Best of luck! -regards, Larry

On Wed, Apr 27, 2011 at 8:53 PM, Noah Roberts <roberts.noah@gmail.com> wrote:
On 4/27/2011 10:42 AM, Matus Chochlik wrote:
On Wed, Apr 27, 2011 at 6:41 PM, Noah Roberts<roberts.noah@gmail.com> wrote:
There is a boost.reflection proposal out there that is meant to work with boost.extension. This one is a bit different in that you're not additionally defining data; instead you declare your reflection as you declare your reflectable type through the instantiation of and inheritance from template metafunctions.
There is also the Mirror reflection library which I plan to submit for review once it is ready.
The project homepage (with links to docs and download page) is located here http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/
Yeah, the original worked like that. We found the manual registration process ungainly. Also didn't do proper inheritance...which maybe yours does. Had trouble looking at the docs and seeing how to use it since the part that probably does all the work (classes.h) isn't linked in with the examples.
You can see some examples of the registering here: http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/doxygen/puddle/html/da/d... http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/doxygen/puddle/html/dd/d... http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/doxygen/mirror/html/d2/d... http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/doxygen/mirror/html/d7/d... Also there is a portable tool called maureen (mirror auto reflection engine) being worked on which pretty much automates the registering process, although it's been on hold a couple of weeks since I'm busy with other projects. [snip/] BR Matus

On 27/04/11 19:53, Noah Roberts wrote: <snip>
Use of mine is more like so:
struct field0 { typedef int value_type; }; struct field1...2 ...
struct my_reflected_type : build_class < var< field0, rw > , var< field1, r > // can't assign through reflection. >::type { virtual ~my_reflected_type(){} DECLARE_PARAM_CONSTRUCTOR(my_reflected_type); };
struct my_reflected_type2 : derive_from < my_reflected_type , var< field2, rw > >::type { my_reflected_type2() : type(( field0() <= some_val , field1() <= some_val , field2() <= some_val )) { // directly access read-only value and assign... var<field1,r>::value = 66.; } };
I also have a ref<> so bases can have fields to abstract types.
So far functions haven't been needed here so there's none but I think I have a handle on how that could be done.
All of the above can be treated as a fusion sequence and/or fusion associative sequence (including the param list).
Building records on the fly with field()<=value syntax was very desired. Comes in handy when you have a function expecting a record with x,y,z fields in it, have those values, but don't want to build the record class.
I created something like this a while back and used it to write a program as an experiment in how crazy it would turn out to be. I didn't support named initialization of the fields; that's a good idea. If you'd like to see, my implementation is here and hereabouts: <https://github.com/jbytheway/nibbles/blob/0ce0577bb11d821614595f465da836f3c011664e/nibbles/utility/dataclass.hpp> but it's not really built for public consumption, and it looks like yours is rather nicer. I did enjoy it for a few reasons. It allowed me to write serialization support just once for all such structs (that was my primary motivation for the experiment), and write a deep comparison operator very easily. However, my conclusion was that the system was ultimately impractical on the scale I was using it for a few reasons: - Compile times were absolutely horrific; though these could no doubt be improved with attention. - I couldn't see an easy way to get a public/private distinction on fields. - Understanding how it interacted with inheritance got rather mind-bending. - The syntax to access fields was just a little bit too tiresome. It could be interesting for use on a small scale, and it would be nice if there were an implementation out there which had done the relevant compile-time optimization and ironed out the wrinkles. However, I would present it as a "Fusion map with extra bells and whistles" rather than a reflection library. John Bytheway

On 4/29/2011 11:18 AM, John Bytheway wrote:
On 27/04/11 19:53, Noah Roberts wrote: <snip>
Use of mine is more like so:
struct field0 { typedef int value_type; }; struct field1...2 ...
struct my_reflected_type : build_class < var< field0, rw> , var< field1, r> // can't assign through reflection. >::type { virtual ~my_reflected_type(){} DECLARE_PARAM_CONSTRUCTOR(my_reflected_type); };
struct my_reflected_type2 : derive_from < my_reflected_type , var< field2, rw> >::type { my_reflected_type2() : type(( field0()<= some_val , field1()<= some_val , field2()<= some_val )) { // directly access read-only value and assign... var<field1,r>::value = 66.; } };
I also have a ref<> so bases can have fields to abstract types.
So far functions haven't been needed here so there's none but I think I have a handle on how that could be done.
All of the above can be treated as a fusion sequence and/or fusion associative sequence (including the param list).
Building records on the fly with field()<=value syntax was very desired. Comes in handy when you have a function expecting a record with x,y,z fields in it, have those values, but don't want to build the record class.
I created something like this a while back and used it to write a program as an experiment in how crazy it would turn out to be. I didn't support named initialization of the fields; that's a good idea.
If you'd like to see, my implementation is here and hereabouts:
but it's not really built for public consumption, and it looks like yours is rather nicer.
I did enjoy it for a few reasons. It allowed me to write serialization support just once for all such structs (that was my primary motivation for the experiment), and write a deep comparison operator very easily.
However, my conclusion was that the system was ultimately impractical on the scale I was using it for a few reasons:
- Compile times were absolutely horrific; though these could no doubt be improved with attention.
Yeah, any time you reflect an object you get a compile-time hit. Just using the objects isn't so bad. So far it's been OK. Another problem I've run into is that the compiler I'm using (VS2010) crashes if a boost::signals2::signal is the member of anything that is also included with a reflected object, if that signal's containing object is included first. We're probably going to work around this by never exposing signals2::signals through public interfaces, using the pimpl idiom to hide them. The connection seems to be OK so far. My guess is that this has more to do with the signals2 library than with mine. The compiler crashed in the same areas in earlier versions of the compiler but is now labeled as passing. It could be that it only passes if you're not also doing a bunch of other template stuff within the same translation unit.
- I couldn't see an easy way to get a public/private distinction on fields.
This could be done with private inheritance probably. Also not sure it would be completely useful though since you can just make extra variable that aren't part of the reflected interface.
- Understanding how it interacted with inheritance got rather mind-bending. - The syntax to access fields was just a little bit too tiresome.
It took some work but to access fields in mine it's: get<outer, inner,inner,inner>(object) There's also a build_accessor that constructs a typedef out of an object type and a sequence of fields (in an mpl::vector for example).
It could be interesting for use on a small scale, and it would be nice if there were an implementation out there which had done the relevant compile-time optimization and ironed out the wrinkles. However, I would present it as a "Fusion map with extra bells and whistles" rather than a reflection library.
Yeah, that's probably a more accurate description. Might be possible to merge into fusion somehow actually. And yes, would be interesting to see what someone who really knows their stuff can do about compilation times...if anything.

On 02/05/11 19:04, Noah Roberts wrote:
On 4/29/2011 11:18 AM, John Bytheway wrote: <snip>
However, my conclusion was that the system was ultimately impractical on the scale I was using it for a few reasons:
- Compile times were absolutely horrific; though these could no doubt be improved with attention.
Yeah, any time you reflect an object you get a compile-time hit. Just using the objects isn't so bad. So far it's been OK.
Actually, thin king back, it wasn't just compile times but also memory usage. You need about 2GB of RAM to compile the program I wrote. My netbook didn't have that at the time.
Another problem I've run into is that the compiler I'm using (VS2010) crashes if a boost::signals2::signal is the member of anything that is also included with a reflected object, if that signal's containing object is included first. We're probably going to work around this by never exposing signals2::signals through public interfaces, using the pimpl idiom to hide them. The connection seems to be OK so far.
My guess is that this has more to do with the signals2 library than with mine. The compiler crashed in the same areas in earlier versions of the compiler but is now labeled as passing. It could be that it only passes if you're not also doing a bunch of other template stuff within the same translation unit.
- I couldn't see an easy way to get a public/private distinction on fields.
This could be done with private inheritance probably.
It's going to be tricky. SFINAE doesn't play nicely with private members, so I don't see how to do it.
Also not sure it would be completely useful though since you can just make extra variable that aren't part of the reflected interface.
That wouldn't be good for my use case because e.g. that extra variable would then not be serialized.
- Understanding how it interacted with inheritance got rather mind-bending. - The syntax to access fields was just a little bit too tiresome.
It took some work but to access fields in mine it's: get<outer, inner,inner,inner>(object)
Hmm.. Yes, that makes sense.
There's also a build_accessor that constructs a typedef out of an object type and a sequence of fields (in an mpl::vector for example).
It could be interesting for use on a small scale, and it would be nice if there were an implementation out there which had done the relevant compile-time optimization and ironed out the wrinkles. However, I would present it as a "Fusion map with extra bells and whistles" rather than a reflection library.
Yeah, that's probably a more accurate description. Might be possible to merge into fusion somehow actually.
And yes, would be interesting to see what someone who really knows their stuff can do about compilation times...if anything.
Have you found the template profiler? John Bytheway

On Tue, May 3, 2011 at 1:18 AM, Noah Roberts <roberts.noah@gmail.com> wrote:
On 5/2/2011 12:06 PM, John Bytheway wrote:
Have you found the template profiler?
No. What be that? Google no good on it either.
participants (4)
-
John Bytheway
-
Larry Evans
-
Matus Chochlik
-
Noah Roberts