On Sat, Jul 13, 2013 at 9:20 AM, Borislav Stanimirov
2. did you avoid using a smart pointer in the introduction example for a
specific reason? if not, I think it would be better to use one, just to avoid people copying this style of code.
Well I didn't want to overburden the reader with the notion of a smart pointer. The messages' first argument is `boost::mixin::object*` so using a smart pointer would also require the constant use of `ptr.get()` to call messages.
I don't agree on the overhead of smart pointers because if a C++ dev don't know what it is, it would be time to learn about it (even if he don't use it in the end). However I agree that using a specific smart pointer type might be misleading. So I suggest using auto and a factory function to abstract the example. Even if someone don't have access to auto, he can at least understand that it's just some kind of pointer.
This makes me think, though. I'll have to think about making the first argument a reference to an object instead a pointer to an object, or allow both (with the cost of an additional copying of the actual arguments).
Indeed, it would make things safer and clearer. Here is how it would look
like in the end:
using namespace boost::mixin;
auto o = create_new_object(); // just a smart pointer to an empty object
// xml_serializer and book_data are some classes in the project
// there are external macros you need to call, to make them available as
// mixins
mutate(*o)
.add
3. is there a way to go through all the instances of the same type? for
example: mutate(o) .add
() .add (); Assuming there is more than one instance composed of book_data, is there a way to list or just apply a function to all currently instanciated book_data?
If not, I think a way to do it would be useful in high performance cases (to update all the components of the same type in one pass, avoiding cache misses and enabling some possible concurrent update setup). But as it's not the core feature I think it would be a nice update.
The library doesn't provide such a feature. There are many axes by which the memory is accessed, so completely avoiding cache misses is impossible. Indeed, there are ways to improve on the cache locality on this or that axis, but that will be at the cost of worsening it on another.
Internally the object separately instantiates the mixins that comprise it and it effectively has a list of pointers to its mixins. If you mutate that object, removing or adding mixins, all of its other mixins, that are already instantiated, won't be touched. To keep all the mixins in a single buffer will require either dealing with big gaps and potentially badly fragmented memory, or moving the mixin data in the memory, which can be slow and WILL break any pointers that reference it (especially bad for classes that have self referencing in some way, like, say google::hash_map/hash_set).
A mixed approach CAN be introduced, but that will require the library users to have deep knowledge of its internal workings in order to choose how their mixins will behave, and that might alienate some users.
To deal with the problem of updating a huge list of objects of the same internal type (or memory problems in general) two things are introduced in the library:
* Object mutators - that speed up mutation by remembering what needs to be done and greatly improve on the performance of the naive `mutate(obj).add.add.add` * Memory allocators that can be set for all mixin allocations or also for the allocations of specific mixins
Still it is the user's job to maintain lists of the objects by whatever criteria they choose (like object that have `book_data` in them). Sure, the library could easily store all kinds of lists by all kinds of criteria, but I fear that this will be memory wasted, since the users know best what and WHETHER to specifically maintain.
From what I understand, the allocator might be enough to allow the user of
the library to set up a pool or dynarray or non-ressizing vector of
components of the same type,
which would be the feature I'm asking for.
I'm not sure though. Would it be problematic to allow the user to provide a
factory function for the component on addition, so that there is a simple
way to
make sure the component is created the way we want?
Something like:
mutate(o).add( [&]{ return world_components.create