Subject: Re: [boost] [type_erasure] Review started (July 18-27,2012)
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2012-07-26 05:57:05


Hi all,

here's my review for TypeErasure.

> Please state clearly whether you think this library should be accepted
> as a Boost library.

Let's answer this upfront: YES!

> Other questions you may want to consider:
> 1. What is your evaluation of the design?

Seen from outside, the design is clean and allows powerful constructs.

> 2. What is your evaluation of the implementation?

I only had a quick glance.

> 3. What is your evaluation of the documentation?

What is there is very good, but we could do with more documentation. A few
suggestions:
- provide a small example of usage of each concept to help new users manage
faster the learning curve.
  I had some difficulties getting istreamable working and had to look at the
tests to finally get it.
- provide more real-looking examples of the sort of the polymorphic range
formatter. The more the better. I'll myself provide one later on in this
message.

> 4. What is your evaluation of the potential usefulness of the library?

Huge! And by this I mean a very interesting programming style which should
be made available also to average programmers.
Which makes the doc even more important.

> 5. Did you try to use the library? With what compiler? Did you have
> any problems?

Yes, on a real private project I do on my free time. I used VC9. I'm in
vacations so I couldn't try gcc and VC10 yet but I'll do this in the next
few weeks.
I got no problem besides a single warning about unused variable (fixed).
I tried the library for 2 different use cases:
- a streamable any (actually I need a boost-serializable any but didn't come
to it yet). One always needs something like this. In the past, I had to
modify a Boost.Any to achieve this. In my design, this helps implement my
low-level saving/loading to/from file easily as the low level layer needs no
knowledge about the types it gets, they're just a bunch of serializable
things.

- improve my MVC (Model-View-Controller) design. Here's my use case: I
started with a classical (OO style) interface-based design a graphical
editor where the user can place and edit items of different kinds on a
drawing area. The interface for these items is something along the lines:
struct IItem
{
...
   virtual void createItem(...)=0; // creates in model
   virtual void deleteItem(...)=0; // deletes from model
...
};

Different views dialogs however need some more concrete item types, like:
struct IType1 : public IItem
{
   virtual void setName(...)=0;
   virtual string const& getName() const = 0;
...
};
struct ISubType1 : public IType1
{
...
};

So far so good but then I want some classes which implement this. Where will
I implement these name members? In a class realizing IType1 (thus having to
redo it for ISubType1)? Or in a class which I also inherit from, in concrete
realizations of IType1 and ISubType1 (thus having either the dreaded diamond
or forwarding methods in all concrete classes)?
And here I have only one concept (naming) and a single type.
Get a few more of each and this will drain the life faster out of a C++
developer than a visit of a yearly vampire festival (unless you're also a
java developer, in which case you're already used to this :) ).
More seriously, the problem here is mixing interface definitions and
realizations. I changed IItem to an ItemConcept:

BOOST_TYPE_ERASURE_MEMBER((Controller)(has_createModelItem), createItem, 1);
BOOST_TYPE_ERASURE_MEMBER((Controller)(has_deleteModelItem), deleteItem, 1);

typedef ::boost::mpl::vector<
    Controller::has_createItem<void(...)>,
    Controller::has_deleteItem<void(...)>,
...
> ItemConcept;
typedef boost::type_erasure::any<ItemConcept> AnyItem;

I can even use composition to build my Type1Concept:

BOOST_TYPE_ERASURE_MEMBER((Controller)(has_setName), setName, 1);
BOOST_TYPE_ERASURE_MEMBER((Controller)(has_getName), getName, 0);
typedef ::boost::mpl::vector<
    ItemConcept,
    Controller::has_setName<void(...)>,
    Controller::has_getName<...()>,
...
> Item1Concept;
typedef boost::type_erasure::any<Item1Concept> AnyItem1;

>From a user perspective, it is equivalent to use an IItem or an ItemConcept,
so that I now have a solution equivalent from the user's perspective, but
much better from the implementer's: I defined interfaces without paying any
dependency and I'm perfectly free to implement as I want, without fearing a
diamond or other ugly surprises.

While it was in front of my eyes, I realized the best part only yesterday.
Let's say my IItem would need a template method
struct IItem
{
...
   // as before
   virtual void createItem(...)=0; // creates in model
   virtual void deleteItem(...)=0; // deletes from model
...
   template <class T>
   virtual void f (T& t); // will not compile
};

Sure, we all know this is not possible (sigh) . However, if I postulate that
I require T to be foo-able for all realizations of this interface, meaning I
can implement f as:

t.foo();

It is anyway good style to document the template parameter's requirements
anyway, so this bears no cost.

Ok, then I can use an any<fooable> in my concept

typedef ::boost::mpl::vector<
    Controller::has_createItem<void(...)>,
    Controller::has_deleteItem<void(...)>,
    Controller::has_f_able<void(any<fooable>&)>,
...
> ItemConcept;

This is really close from virtual template methods.

There is only one thing missing to be able to throw away all these
interfaces: the ability to navigate through dynamic/static cast in the
hierarchy. TypeErasure supports upcasting of concepts but not downcasting.
According to Steven, this would be possible.
I won't make it an acceptance condition, but I could make good use of this
feature. My use case: different view items get an IItem, then a view Item
for Type1 would safely cast down its IItem to IType1. This is at the moment
not possible with TypeErasure. I view this as a killer feature, so I can
only advise providing it at a later point.

One last request: I would like the possibility to read the concept of an any
through a metaprogram. I found this:
    /** INTERNAL ONLY */
    typedef Concept _boost_type_erasure_concept_type;

I try to avoid using internals, could this be made part of the public
interface?
Use case:
My view item for Type1 gets an any<Type1Concept> and needs a property page
for it. Obviously it would need name setting/showing, which other
any<ItemConcept> would not. The property page dialog could, with a simple
template function, get the concepts supported by an any and build the dialog
accordingly. I would thus be able to write a single generic dialog class for
all types.

> 6. How much effort did you put into your evaluation? A glance? A
> quick reading? In-depth study?

About 10-15 hours trying on real, not toy code.

> 7. Are you knowledgeable about the problem domain?

I've used Boost.Any/Function several years and made my own serializable any.

I want to thank Steven for providing this great library, which I will use in
any case, accepted or not.
Thanks Lorenzo for managing the review and getting it scheduled so fast.

Christophe