Boost logo

Boost :

Subject: Re: [boost] Boost.Mixin library preliminary reviews
From: Borislav Stanimirov (b.stanimirov_at_[hidden])
Date: 2014-02-11 02:22:04


On 02/07/2014 09:25 PM, Klaim - Joël Lamotte wrote:
>
>
> 1. The introduction page would benefit from having a short but demonstrative
> example before or after the list of features, but surely before
> getting into "comparisons".

Indeed and I'll think about adding something.

>
> 2. There is another meaning of mixing that is D mixin, which I believe is
> highly differnt, but maybe a mention to clarify that it's different would
> help someone used to D.

Check. Will do.

>
> 3. You are talking about mixins in Ruby without a short description of what
> it is
> or any link to an explanation.

There's a link at the top of the page in the introduction. I'll add it
to the Ruby Mixin comparison too.

>
> 4. The introduction page have a lot of assertions about the performance of
> the library
> but no link to a page with performance comparisons. I also don't see one in
> the index.
> I would like to see one.

I'm working on a more detailed performance analysis. Right now you can
find some info about messages in the advanced topics here:
http://ibob.github.io/boost.mixin/boost_mixin/advanced.html#boost_mixin.advanced.performance

>
> 5. I'm not at ease with the macro defining the mixins and messages, but I'm
> guessing
> it would be hard to do otherwise...

Impossible without having the user write many tens of times as much code
for defining messages, and about ten times as much for mixins.

>
> 6. In the basic example, you forgot to specify that the namespace is
> boost::mixin.

Check. Will do.

>
> 7. Can the definitions be inlined so that a header-only library can be
> implemented using boost::mixin?

Theoretically yes, however it won't be possible to use this library in
another dynamic one. Since the library has a central instance (called
domain) it's crucial that if two modules use mixins (say the executable
and a dynamic library) they share this instance. The way to do it
is if Boost.Mixin is a dynamic library used by both. So if you inline
Boost.Mixin, you're bound having your software in a single module (as
you are when linking statically to the library)

>
> 8. I'm not totally sure but I find the basic example maybe a bit more
> complext than it could be. That's only intuition though, I don't have a
> specific suggestion. Yet.

Are you talking about the one in Basic Usage here:
http://ibob.github.io/boost.mixin/boost_mixin/basic.html

... or the one in examples here:
https://github.com/iboB/boost.mixin/tree/master/libs/mixin/example/basic

>
> 9. I think I mentionned in the previous Boost.Mixin thread that I would like
> to have a simple way to process the full range of mixins of the same type,
> ignoring which objects they are "attached" to.
> However I don't see that feature in the documentation.
> The messaging system don't exactly match what I'm asking and I expect
> that if the user knows the exact mixin type to process it would be faster to
> just go through all the mixin and do the processing on each instance.
> This of course, assume that the mixin objects are stored "somewhere"
> together, per type.
>

This is possible with allocators. It is not the default behavior. By
default the mixins for an object are each allocated separately when
the object is construced.

You can add an allocator to a mixin (I'll add this to the documentation
in the next couple days) with

`BOOST_DEFINE_MIXIN(my_mixin, my_messages &
boost::mixin::allocator<my_allocator>());`

... and then ensure that this allocator of puts the mixins in a single
block of memory.

Since it's not properly documented yet, the only example of this is in
the tests, here:
https://github.com/iboB/boost.mixin/blob/master/libs/mixin/test/allocators.cpp

> 10. When dispatching a message to a sequence of objects, depending on the
> object's mixins, it will or not do something.
> I would like to see a comparison of performance between messaging
> objects which have at least one mixin reacting to the message VS objects
> which have no mixin reacting to the message (but do have mixins).
> Basically I'm wondering if messaging cost is lower when there is no actual
> message handler in the mixins of an object. If not, this limits messaging
> to events processing (which is fine), but makes it almost impractical for
> mixin state updating (which is the what I want to do in [9]).

Calling a message for an object that doesn't implement it, is a runtime
error (like calling a method for plain C++ class that doesn't implement
it is a compile time error). If you want something like default message
behavior whether it's nothing or something, you'll have to add mixins
that implement it (with nothing or something) to your objects.

>
> 11. So far I don't see the usefulness of message priority. Could you give a
> demonstrative example?

For unicasts:

For temporary mutations, explained in the messages tutorial here:
http://ibob.github.io/boost.mixin/boost_mixin/tutorials.html#boost_mixin.tutorials.messages

 From the page:

----------
Now lets try stunning our enemy. We'll just add the stunned_ai mixin
and, because of its special think priority, the calls to think from then
on will be handled by it.

     mutate(enemy).add<stunned_ai>();
     think(enemy); // don't do hostile stuff, because you're stunned

Now let's remove the stun effect from our enemy, by simply removing the
stunned_ai mixin from the object. The handling of think by enemy_ai will
resume as before.

     mutate(enemy).remove<stunned_ai>();
     think(enemy); // again do hostile stuff
----------

The fact that `stunned_ai` implements `think` with a higher priority
helps us add it temporarily and then remove it as opposed to

1. Having to remove and re-add `regular_ai` which can potentially be a
heavy or hard initializing operation
2. Taking care to remove and re-add other mixins that implement `think`,
like there is in the example for `enemy_ai` and `ally_ai`

For mulitcasts:

To determine the order of execution. Like the `trace` message in the
same tutorial.

>
> 12. It is not clear to me why there is need for a separate macro for const
> messages.

Const messages are, as you've perhaps seen, bound to const methods and
generate functions whose first parameter is `const
boost::mixin::object&`. Indeed you can have a single macro that does
this, but it will need to have a parameter for this, say instead of

     BOOST_MIXIN_CONST_MESSAGE_1(void, foo, int bar);
     BOOST_MIXIN_MESSAGE_0(void, baz);

you could have

     BOOST_MIXIN_MESSAGE_1(void, foo, int, bar, BOOST_MIXIN_CONST);
     BOOST_MIXIN_MESSAGE_0(void, baz, BOOST_MIXIN_NON_CONST);

... or something similar. I chose the first syntax.

>
> 13. I feel like your game example in Tutorials is a bit flawed.
> For example, you use mutation to change the behaviour of the ennemy,
> but in the next section you explain that mutation is a slow process.
> Basically, that's not convincing, no game dev would do it like that I
> believe.
> However, it's only the example that is not convincing, not the principle.

When I say "slow" I mean that it's not suitable to do for all of your
objects every frame. Mutations typically lead to allocations and
deallocations and that's the slowest part of them.

The example's flow is something like

1. "stun"
2. ... many frames with no mutation
3. "remove stun"

I should (and will) add a more detailed explanation for the mutation
costs. But a couple of mutations should be able to cause a significant
framerate spike (especially if you use custom allocators for some mixins
you add and remove often)

>
> 14. `object_type_template` seems very important but there is no section
> explaining what it is and how to use it until in the middle of the second
> Tutorial.
>

It's not that much faster than the simple mutation with `mutate`. It
mainly saves you from writing code and looks better.

It does save you a std::map lookup, but that's not much compared to the
potential allocation of mixins that will happen, whether you do use it
or not.

>
> 15. In the Appendix you explain what an ECS is, but it's uncomplete and
> don't explain all the benefits.
>

Noted. I will try to expand it.

> There are different types of ECS:
> a) component types inherit from a base type, components instances are
> contained/owned by the entity instance;
> b) same as a) but components are actually gathered in arrays by types,
> entities instances only have references (pointers or something else)
> to component
> instances;
> c) entities are just ids, components have ids, so an entity is defined
> by all the
> components having the same id;
>
> <snip>
>
> I'm not sure what Boost.Mixin actually implements here, but
> if it's neither b) nor c), I would consider it unpratical in most action
> games.
>
> As a side note: If there is a way to achieve processing an array of
> components as one batch, then I would like the container of components to
> _not_ be global (maybe optionally), so that if I use it, I can separate the
> processing into several "world sections" that can be processed separately.
>
>

As I mentioned before. It could be something like b) but only for some
mixins, that you've chosen, by adding custom allocators.

Without custom allocators it is indeed neither b) nor c)

-- Borislav


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