Boost logo

Boost :

Subject: Re: [boost] Formal Review Request: TypeErasure
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2012-06-16 01:08:05


AMDG

On 06/15/2012 07:19 PM, Daniel Larimer wrote:
>
> On Jun 15, 2012, at 10:36 AM, Hite, Christopher wrote:
>
>> Daniel Larimer:
>>> I suspect that you could achieve generic 'value semantics' for any pure virtual interface via a very simple macro + other C++11 features. I think the cost of making a call with the following code would be the same as using pointer semantics via a virtual call.
>> Wow thanks for proving my point. So value<T> requires T to be copyable.
>>
>> Why do you use virtual inheritance? It does cost something, I think a extra word in the object which gets added to this before calling stuff on the interface.
>
> I have updated my example and taken it a bit beyond proto-type code. In the example below I demonstrate interface 'composition', added operator (ostream,+,etc) support and completely eliminated the need for a macro to make things work. I also demonstrated overloading operator() to create a 'boost function' type erasure. It will now store 'non class types' as it no longer inherits from the stored type so it could store non-class functions as well. With a bit more work I think I could have any< function<Signature> > working. The code no longer depends on variadic templates and should compile with VC2010.
>
> Virtual inheritance is needed to solve diamond inheritance problem and to support interface composition (you only want one instance to actually hold the data)
>
> I think that the header (any.hpp) just about covers value semantics. A slightly modified version could provide pointer and reference semantics. Pointer and reference semantics would not need to heap allocate and I believe I can avoid heap allocation for all 'small' types with a little bit of template logic.
>
> https://github.com/bytemaster/mace/blob/master/libs/stub/include/mace/stub/any.hpp
>
> https://github.com/bytemaster/mace/blob/master/libs/stub/include/mace/stub/any_example.cpp
>
> If I went back to the MACRO based approach combined with variadic templates I could eliminate one virtual indirection, but I don't know if that is enough to justify loss of portability and the use of a MACRO. I suppose there is room for both with/without a MACRO for 'fast' versions.
>
> With my new header I don't think I would ever use the TypeErasure library under consideration because of its three fatal flaws:
>
> 1) Lack of readability... I could hardly follow the examples and without documentation your typical coder would never be able to follow the code or know what interface they need to expose.
>
> 2) Lack of writability... Not only is the TypeErasure library hard to read, it is hard to figure out how to use it to do what you want.
>

Okay. Consider:

template<class T = _self>
struct member_add1 {
    static void apply(T& t, int i) { t.add(i); }
};

template<class T = _self>
struct member_add2 {
    static void apply(T& t, double d, std::string s) { t.add(d, s); }
};

template<class T = _self>
struct member_sub {
    static int apply(T& t, int i) { return t.sub(i); }
};

namespace boost { namespace type_erasure {
template<class T, class Base>
struct concept_interface<member_sub<T>, Base, T> : Base {
    int sub(int i) { return call(member_sub<T>(), *this, i); }
};
}}

template<class T = _self>
struct my_interface :
  mpl::vector<
    member_sub<T>,
    member_add1<T>,
    member_add2<T>,
    ostreamable<T>,
    callable<int(int), T> >
{};

namespace boost { namespace type_erasure {
template<class T, class Base>
struct concept_interface<my_interface<T>, Base, T> : Base {
    int add(int i) { return call(member_add1<T>(), *this, i); }
    int add(double d, std::string s)
    { return call(member_add2<T>(), *this, d, s); }
};
}}

This is about the same amount of code as your example.

What do you have to keep track of here:
- primitive concept defs
  - Use of the placeholder _self
  - The static apply function
- concept_interface:
  - Inheritance from Base is required
  - The argument of the concept must match the placeholder
  - boost::type_erasure::call
- Use of MPL Sequences to combine concepts

With your code:
- virtual inheritance
- Use of forward_interface
- inheritance from any_store<T>
- The implementation is a specialization of the interface
- this->val

With some macros my code becomes. (This macro is fairly
easy to write, since it's just a slightly more generic
version of the macros I used to define my own operators).

BOOST_TYPE_ERASURE_MEMBER((member_add1), add, 1);
BOOST_TYPE_ERASURE_MEMBER((member_add2), add, 2);
BOOST_TYPE_ERASURE_MEMBER((member_sub), sub, 1);

template<class T = _self>
struct sub_inter : mpl::vector<member_sub<T> > {};

template<class T = _self>
struct my_interface :
  mpl::vector<
    member_sub<T, int>,
    member_add1<T, int>,
    member_add2<T, double, std::string>,
    ostreamable<T>,
    callable<int(int), T> >
{};

> <snip>
> So perhaps we should change the nature of the discussion on this library from
>
> "should we even have or use such a tool?"
>
> to
>
> "If you are going to use such a technique, what is the best library for the job?"
>
> If there is enough interest and we can establish some more through requirements, I would gladly polish up my any<> interface to complete a simple and small library for doing this.
>

Here's why I believe that my library is superior:
- You don't have a good way to represent
  boost::type_erasure::equality_comparable<>,
  and you have no way to represent
  equality_comparable<_a, _b>. The former
  is critical, the latter less so. (Concepts
  involving multiple types or associated types
  appear all the time in generic programming.
  Try implementing a type erased version of your
  favorite STL algorithm).
- The type erased ostream operator in your example
  has it's arguments backwards. Doing it
  right adds extra complexity.
- Virtual inheritance makes your objects bigger
  and increases the cost of dispatching.
- You can't beat a macro interface for keeping
  the base concept definitions simple.

In Christ,
Steven Watanabe


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