
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