Subject: Re: [boost] Boost.Mixin library preliminary reviews
From: Klaim - JoÃ«l Lamotte (mjklaim_at_[hidden])
Date: 2014-02-11 11:54:05
On Tue, Feb 11, 2014 at 7:22 AM, Borislav Stanimirov <b.stanimirov_at_[hidden]>wrote:
>> 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:
> 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 ).
> 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.
So, If I have a set of objects which I don't want to know the associated
components, but I do want to send a multicast message that will be processed
only by some of the components, currently I can't do this because I would
get an error if one of these objects have a component which don't have a
handler for that message?
Isn't that limitting a lot the usage of mixins/components?
>> 11. So far I don't see the usefulness of message priority. Could you give
>> demonstrative example?
> For unicasts:
> For temporary mutations, explained in the messages tutorial here:
> 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.
> 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.
> 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`
I believe that this example in practice would be implemented in another way
(behaviour tree or finite state machine)
so it's not really convincing in practice, but I see part of the point.
> For mulitcasts:
> To determine the order of execution. Like the `trace` message in the same
>> 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
>> 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.
Which is why I'm pointing to the fact that game devs would totally avoid
such practice, which is why I find that example unconvincing.
I'm sure another case could be found that would be more convincing.
> The example's flow is something like
> 1. "stun"
> 2. ... many frames with no mutation
> 3. "remove stun"
If there is allocation and deallocation, it's rarely affordable for a game
dev, at least in action games.
To bo short, it's known to be bad practice in the field. Which is why I'm
pointing that. (even if it's not an actual library problem, more a
> 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)
Would it be possible to avoid allocations?
It looks liike this system have similar properties to Boost.Statecharts
which allocate/deallocate states and use constructors and destructors as
entry and exit points.
I believe that Boost.MSM is actually a better (more efficient) way to do it
as the whole thing is pre-allocated.
I don't know how you could follow a model closer to Boost.MSM but the
allocatoin/deallocatoin for a mutation seems like it could be avoided under
>> 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
>> contained/owned by the entity instance;
>> b) same as a) but components are actually gathered in arrays by
>> entities instances only have references (pointers or something else)
>> to component
>> c) entities are just ids, components have ids, so an entity is
>> by all the
>> components having the same id;
>> 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
>> 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
>> 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)
Ok that was not clear: you mean that the user have to provide allocators
for mixin types to allow
the behaviours of b) and c) and concurrent update of mixin instances?
If yes, could you provide at least an example of upating mixing instances
in a pool or something, as documentation?
I think helping the user setting up easily such system would help devs
getting interested in this library.
Just saying that you can provide allocators suggests that you'll have to do
the plumbery work to make the library
work as I think most people would expect (with mixins stored in something
like vectors or pools per type).
Could you provide helpers for that?
Thanks for your time.