|
Boost : |
Subject: Re: [boost] [Boost-interest] C++ library for runtime-concepts (type-erasure)
From: Daniel Larimer (dlarimer_at_[hidden])
Date: 2011-02-14 11:19:42
On 2/14/11 5:14 AM, "Germán Diago" <germandiago_at_[hidden]> wrote:
> 2011/2/14 Daniel Larimer <dlarimer_at_[hidden]>:
>> I have posted Boost.IDL to github complete with documentation here:
>> http://bytemaster.github.com/boost_idl/index.html
>>
>> https://github.com/bytemaster/boost_idl
>>
>> The library is header only. It is included as part of the Boost.Defrag
>> "incubating" projects.
>>
>
> I haven't carefully read the documentation (sorry, have no time now),
> but I thought a lot about a new serialization library. My opinion
> is that this library couples two things together: interfaces and reflection.
>
> I think that the correct approach to this is:
>
> 1.- Build a general runtime concepts library (without reflection)
I would welcome such a solution; however, everything idea I have come up
with in this regard requires either verbose/ugly macros or almost as much
work as manually rolling your type erasure according to a well-defined
pattern.
> 2.- Build a reflection mechanism that would be possible for every c++
> type to use (non-intrusive).
If you do not mind C++0x dependency and verbose macros, Boost.Mirror does
this very well. Older versions of Boost.Mirror do not require C++0x and the
developers of Boost.Mirror are also creating a tool that will auto-generate
the required macros. My feeling is that if your code requires that much
reflection and you are willing to use a pre-processor then chances are your
compile times and binary sizes will become huge. If you are using a
pre-processor then you might as well generate code directly rather than
using templates and should probably be using a different language.
A simple version of run-time reflection, useful for serialization:
This is the easy part, create a macro that does this:
DEFINE_VISITOR( InterfaceType, (member, 1)(sequence,3,optional) )
template<typename VisitorType, typename ExtraProperties>
void visit( Visitor& v, InterfaceType& i,
const char* name, ExtraProperties prop )
{
v.accept( i.member, "member", 0 );
v.accept( i.sequence, "sequence", 0 )
}
The above works well for serialization, but loses the member pointer for
reflection. So perhaps the following alternative would work:
v.accept( i, &InterfaceType::member, "member", 0 );
I would hope that any reasonable compiler would cause the performance of
both variations to be identical considering all of the information required
is present. However, I suspect that the first version would probably
involve one less 'indirection' and thus perform better for serialization
operations, while the second would be better for reflection.
Any type can use the BOOST_IDL_INTERFACE() macro to define its
reflection without using it for type erasure.
> 3.- Build serialization and other reflection mechanisms in top of
> these two different libraries.
>
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 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:
>
> class MyClass {
> typedef MyClass this_class;
>
> std::string val_;
> float f_;
> public:
> typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t;
> };
>
I suspect that your tuple approach could be combined with my visitor
approach to offer two methods of reflection, runtime and compile time:
DEFINE_MEMBERS( TYPE, (val_)(f_)...() )
typedef boost::fusion::vector< &TYPE::val_, &TYPE::f_, ... > TYPE ## MEMBERS
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.
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.
Correct me if I am wrong, but doesn't boost::fusion::vector<> explode
compile times as the number of elements grows? Is tuple better? Would
attempting to reflect an type with 50 fields in this manner be totally
unfeasible?
>
>
> And the rest was done by a general serialize member function (actually
> a family with boost::enable_if).
> With c++0x I could pass the variable names in tuples if we had
> user-defined literals and constexpr (at least, I think so). With this
> info, it's very easy to serialize objects in c++ (although I didn't
> study every single problem like inheritance and so on).
>
> template <class T>
> std::string serialize(const T & t);
>
> With reflection for members and runtime concepts, a framework for RPC
> can be built on top of those general and
> useful by themselves library.
>
> I hope my opinion helped you.
Your ideas are good in theory and they are my ideal as well, but I have yet
to reduce it to practice. Any ideas on that would be useful.
>
>
> ______________________________
>> Unsubscribe & other changes:
>> http://lists.boost.org/mailman/listinfo.cgi/boost
>>
> _______________________________________________
> 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