
On Tue, Feb 11, 2014 at 7:22 AM, Borislav Stanimirov
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
Yes.
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.
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 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
(); 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
(); 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 tutorial.
Ok.
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.
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 documentation problem)
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 some conditions?
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)
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.