Boost logo

Boost :

Subject: Re: [boost] [Boost-interest] C++ library for runtime-concepts (type-erasure)
From: Germán Diago (germandiago_at_[hidden])
Date: 2011-02-15 04:58:35


>> I looked at Boost.Mirror some time ago, but I think that, for my own goals,
>> that is a too heavyweight dependency.

> This certainly may seem so from the point of view of your library.
> But if you look at the bigger picture then you'll see that it will be
> many times used in applications using other utilities and libraries,
> some of which could also employ reflection, and then having a single
> reflection facility that can provide meta-data for all of them is a great
> advantage. The slight overhead of the compile-time part of Mirror
> compared to what you are proposing is IMO worth it. The reusability
> of meta-data provided by Mirror is one of its strong suits, if I may
> say so :)
>

I think you're right. I can reconsider my decision, but for now I'll be trying
to improve my design on type erasure. Once that is done, the only thing left
is to choose how to generate reflection information. My top priority is not to
be intrusive if that can be achieved.

>>> A simple version of run-time reflection, useful for serialization:
>>>    It is funny you mention this, I am actively working on adding
>>> serialization features to Boost.IDL with the goal of providing more control
>>> over the 'Archive' format than Boost.Serialization.  Specifically, I want to
>>> support JSON / Protocol Buffer serialization approach to support
>>> forward/backward compatibility.
>>
>> I think that Boost.serialization library is a good library, but if it
>> were written nowadays,
>> it would be done in another way. I think that the correct way when
>> c++0x is implemented
>>  with some trait that identifies the members that you want to serialize, and,
>> after that, return an in-memory object, like a string. Having the
>> information provided
>> by those members, you could implement generic
>> and custom serializations: binary, json, and whatever, without having
>> to code a special-purpose
>> format for your specific library. This way we can make libraries useful
>> to more people.
>
> This is what the visitors in the old (non C++0x) version of Mirror were doing.
> In the new version this will be implemented by special manipulator classes
> that will be generated by a mechanism similar to the factory generator
> that already is in Mirror.
>
> This way you will be able to do not only serialization/marshaling-like
> things but you'll be able to generate a (reusable) GUI for the inspection
> or even manipulation of existing instances of every 'reflectible' type.

This sounds great.

>>
>>
>>>
>>>>
>>>> I tried (but it's incomplete) a new reflection approach, and I think
>>>> that with c++0x will be possible. The goal for this reflection library
>>>> was
>>>> serialization, so it wasn't a general reflection framework, but it was
>>>> good enough to serialize objects.
>>>>
>>>> My approach was to use a tuple that described every c++ member that a
>>>> class had. It looked something like this:
>
> If you need just this I think you can use Boost.Fusion. But, the above
> still applies. It focuses on a single task what makes the meta-data
> unusable for some other purposes.

Ok. The correct way is to reuse libraries as much as possible so that bugs can
be corrected always in the same place. But at the same time I would
like a syntax
that avoids macros as much as possible. For example, my std::tuple
inside MyClass
uses a macro, but a very obvious one. The rest is understandable. There
are many ways to write complicated macros, so I try to avoid them except when
there is no other practical way.

>>>>
>>>> class MyClass {
>>>> typedef MyClass this_class;
>>>>
>>>> std::string val_;
>>>> float f_;
>>>> public:
>>>> typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t;
>>>> };
>>>>
>>>
> [snip]
>>
>>
>>> The trouble is that even though we have compile time access to all of the
>>> member pointers, we have lost the 'name'.  With some fancy magic to generate
>>> a const char* with external linkage one might be able to get the name into
>>> the template parameter as non-type template parameter.
>>
>> With constexpr + user-defined literals, I think this can be done:
>>
>> template <char...C>
>> struct Var_Name {
>>     //expand here C...
>> };
>>
>> And with user-defined literals:
>>
>> constexpr template <char... C> Var_Name<C...> operator _var();
>>
>> now:
>>
>> //We didn't loose the name!!!! Good c++0x...
>> typedef tuple<Var_Name<"name"_var>...
>
> I've tried to use compile-time strings with Mirror twice, the first time
> with MPL and the second time with C++0x variadic templates,
> and the result was an increase in both compile-times and executable
> size (somewhere between 3 to 7 percent depending on the usage).
> Unless you really, really need to use a compile time string, consider
> using a simple literal.

Even if that's true, I think that if compile times don't grow much, compile-time
strings should be the right way to put string information. I've tried much and
very hard over time, and this avoids my hated macros a lot (with c++0x).

>>
>> This should be valid c++0x.
>>
>>>
>>> Even if you achieved complete static reflection with the above method, it
>>> would still not enable you to 'build' types with arbitrary member variables
>>> and methods.   Perhaps using boost::fusion fused parameters you could
>>> simplify the number of permutations enough that it may be possible to
>>> generate a 'class' that given a method signature template parameter
>>> implements 'name' in terms of that signature.
>>
>> I think that's not possible in c++, but I'll try to investigate once I
>> have some time.
>>
> [snip]
>
>> - Enable 'building' types with arbitrary member variables. -> This one
>> is pretty difficult.
>
> I'm not sure if I understand correctly what you mean but if
> you are referring to transforming something like this...
>
> struct some_type
> {
>  T1 m1;
>  T2 m2;
>   ...
>  Tn mn;
> };
>

That was a goal of Boost.IDL interfaces, but I tried to make a summary of
what would be useful to take into account to design things that don't overlap.

>
> then it will be doable with Mirror (it actually already is
> in the old version and partially also in the new one
> but still undocumented).

I'll consider using Boost.Mirror. In fact, it would be *the right way* to add
services that use reflection, such as serialization. But, you know, I
want to avoid
macros as much as possible (except when registering runtime information, which
I think it can't be done in other way). So I would like to find some
way to non-intrusively
(like iterator_traits) add compile-time information for my classes.

>
> BR,
>
> Matus
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk