The top search terms for this blog seem to be “flat hierarchy C++”, so this is something I should address.
I had originally intended on writing a crude implementation in Python, to demonstrate the consept, leaving an actual efficient implementation as an exercise for the reader (possibly implementing it myself for a future post), but perhaps it would be more useful to think about it sooner. In this post, I will write a few short sentences to outline my thoughts on implementing a flat hierarchy in C++, which will hopefully provide readers with some ideas to implement this themselves.
There are two ways of implementing flat hierarchies which I am currently interested in exploring, though I’m sure theres more. I will briefly explain these here:
- Independent components which communicate over an anonymous shared-nothing messaging system. This works because the messaging is transparent – a component never knows which other components will receive its messages, if any. A receiving component likewise never knows which components sent the messages which it is receviing. This anonymous message sending means that components may be added or removed at will and other components will never know. Obviously it may not logically make sense to do this – if a component relies on certain messages to work and you remove the component which generates the messages, then obviously the first component cannot fnction – but it will not fail either, it will wait around until you add a component which does generate those messages back into the system. Each component is a node in a flat hierarchy.
- An entity system. In this context, an entity system is an alternative to object oriented systems where an object is simply a collection of traits and is a technique borrowed from the game development community. How this object behaves is determined by the traits it has associated with it. Traits may be added or removed at runtime. Each object is independent and can only communicate through its traits. Since traits can be added and removed dynamically, the system maintains a flat hierarchy. Objects can be processed independently and concurrently. The building of entity systems is the subject of my “Building a Flat Hierarchy” series of posts, so be sure to check those out, if interested.
Since entity systems are reasonably complex and are being covered in their own series of blog posts, I will not talk about them here. Instead I will briefly talk about the independent component method of building a flat software hierarchy.
Ok, so hopefully at this stage you have a reasonably good idea of why this system works. If theres still confusion, please leave a comment and I’ll try and clear things up. Time to move on to implementation details.
I’m not going to implement the entire thing and just give out the code for people to use because that would take more time than I have to write this post. Also, different projects have different requirements and a system I build now may not be ideal for whatever you have in mind. Best to leave it up to you to fine tune the details to your needs. The version presented here whould give you ideas, but it won’t be terribly good or efficient.
Lets start with a component:
class Component {
private:
static std::map<unsigned int, std::vector<Component*> > eventMap;
protected:
// Register for all events of type "type".
void registerForEvent (const unsigned type);
// Send an event.
void send (const Event* const event);
public:
// Event handler, called when an event, which is being listened for, is received.
virtual void eventReceived(const Event* const event)=0;
};
And the implementation:
std::map<unsigned int, std::vector<Component*> > Component::eventMap;
void Component::registerForEvent (const unsigned int type) {
eventMap[type].push_back(this);
}
void Component::send (const Event* const event) {
std::vector<Component*>& components = eventMap[event->type];
for (std::vector<Component*>::iterator i = components.begin(); i != components.end(); i++) {
(*i)->eventReceived(event);
}
}
All events are derived from the Event base type:
class Event {
public:
Event (unsigned int t) : type(t) {}
virtual ~Event () {}
const unsigned int type;
};
Lets test this with some stupid events:
enum EventIdentifiers {
QUIT_EVENT=0,
PRINT_HELLO,
PRINT_MESSAGE
};
class MessageEvent : public Event {
public:
MessageEvent () : Event(PRINT_MESSAGE) {}
virtual ~MessageEvent () {}
std::string message;
};
Now I’ll implement some very simple and crude components, just to have something that can be run:
class HelloPrinter : public Component {
public:
HelloPrinter () {
registerForEvent(QUIT_EVENT);
registerForEvent(PRINT_HELLO);
registerForEvent(PRINT_MESSAGE);
}
virtual ~HelloPrinter () {}
void eventReceived(const Event* const event) {
if (event->type == QUIT_EVENT) {
std::exit(0);
}
else if (event->type == PRINT_HELLO) {
std::cout << "Hello!\n";
}
else if (event->type == PRINT_MESSAGE) {
std::cout << "Message: " << static_cast<const MessageEvent*>(event)->message << "\n";
}
}
void sendQuit () {
Event event(QUIT_EVENT);
send(&event);
}
void sendHello () {
Event event(PRINT_HELLO);
send(&event);
}
void sendHelloMessage (const std::string& message) {
MessageEvent event;
event.message = message;
send(&event);
}
};
Ok, almost done. Lets tie it all together:
int main (int argc, char** argv) {
HelloPrinter a, b, c;
a.sendHello();
b.sendHelloMessage("Hi from b");
c.sendQuit();
}
This should print “Hello” three times followed by “Hi from b” three times and then it should quit.
Ok, I’ll be the first to admit that this implementation is extremely limited and suffers from a bunch of flaws – BUT hopefully you can see the ideas and use that to implement a much more powerful version. Before I leave you to experiment, let me briefly mention some improvements which could be made to the above code. I’m sure you can think of many more too:
- Should the sending component receive its own events? Perhaps the sender should be able to choose.
- Should events be processed right away? This is useful for simple programs, but for large systems, you may end up in situations where some components never get to process events because other events are always processed first. A good solution would be to queue up all events, instead of sending them right away and then dispatch them when all event handlers have returned.
- Should events be processed sequentially? It may be better to process them in threads. One good solution would be to have a pool of threads which will execute the event handlers. Since communication is done through immutable events, the handlers can all run at once.
- The events themselves can be constructed from a memory pool to make creating and destroying events (event large events) a fast and cheap operation.
At some point in the future, I will implement (because I will need an implementation soon) and explain an implementation which has all of those features and probably some others too. I cannot commit to a date though, could be tomorrow or it could be next year.. who knows.
I hope that seeing the idea in code has helped you understand what it is I’m talking about and hopefully this will spark your imagination and creativity and perhaps motivate you to implement your own, more advanced, efficient and powerful versions. I’d love to hear what people come up with, so if you do implement this yourself, I’d appreciate a quick comment!

Any thoughts on the execution model of a flat hierarchy? In your case, the event processing is separated into its own function, but it is used just like a stacked hierarchy where each component executes the events of all other components. Very nice example though.
Here are a few things you may want to consider if you want more flexibility even though the initial setup of this system is a little more complicated.
First is that components should never execute anything in another component except to store a message. But at no point can this call another function to process that message. If the other component has its own thread, then that thread can process it, otherwise you need to wait until the component is completely done before starting up the other component that received the message.
Second is that you need an execution manager. Either all components have their own threads, or you can have a separate function that executes each component in turn that have messages waiting in their queues (you could even have this threaded as well with locking mechanism in place for the message passing so that each core can execute a component).
This is just me, but the true meaning of flat hierarchy is one where you can move a component (or sub-component) anywhere, even to another machine. Or where you can group them together into compound components. If you include a call to send which then processes that event in another component, you lose the ability to group or separate. They are forever coupled to each other.
IOW, (again for me) a flat hierarchy is where we, as humans, can group or separate components, but where the machine(s) can NEVER make use of this to execute the code.
You may have different plans and your example is certainly the right way to go for an example as it contains all the prerequisites before going to a dataflow model. All it needs is a modification of the send routine so that components can queue incoming messages and a component queuing mechanism for a kind of round robin execution handler (components get inserted into the execution queue when they have a message in their incoming queue).
To reiterate, flat hierarchies are useful to me because they allow the developer to create arbitrary groupings anywhere in the software that help visualize the software in a more comprehensive fashion (higher level). But where those groupings mean absolutely nothing (other than perhaps substituting the implementation) to the execution manager, enabling code to be automatically distributed. So developers get to see the “big picture” or small details as they wish without adding extra complexity to the runtime (once it’s set up) which allows it to do automatic distribution.
What do you think? What are your views on flat hierarchy that make it interesting?
Here’s just one example of an advantage that I see. When you group functions together into another container function, you’re essentially grouping not just the functions inside your container function, but also EVERY single function that is called at all depths of execution. That’s a stacked hierarchy. A flat hierarchy allows me to group together only PART of the depth. I could group ONLY the first function calls, but not the second level of execution nesting. Of course, that makes no sense in normal C++, but it does if you create components with the two added points above because components are individual entities. This would allow one to create libraries that not only gets called, but also that connect to other components on the other side. IOW, you could use libraries ANYWHERE and for ANY amount of code. Right now, macros and templates mostly serve this purpose, but obviously the need is there.
Am I off base with what you are thinking about? Those are some of my views. But I’d like to know more about how you’re going about it. How do you see this being used?
(And apologies for the long comment.)
Comment by Vorlath — July 24, 2009 @ 11:59 pm |
Thanks for the comment! You brought up some great points, though ones I have already thought about. I guess perhaps I should have put more effort into pointing out what the shortcomings were and maybe write a quick note on how they can be removed. I guess you just did that for me
I will rewrite this in a future post though – without the limitations.
You’re right on the mark. This is the exact reason why I stated that this is a crude first example which can still be greatly improved. I wanted to start simple though and slowly move towards my ideal implementation.
The biggest flaw with this version is, like you said, that sending a message will still call the function from the other components. This was only done to keep the implementation simple. What I would really want to do, in the send function, is to queue the message to be processed – not actually process it right away. This means that components can (and I believe actually should) be run in separate threads, either one thread per component, or a pool of threads where each thread can processes one or more components sequentially. This, potentially, allows components to run in parallel and also, depending on how messages are managed and passed to the receiving components, would also allow them to run in seperate OS processes or even on other machines.
My goal with this system is definitely to allow components to be added and removed from a system dynamically, at runtime, without breaking the rest of the program – as well as allowing for the possibility of running components on different machines.
Messages should be immutable chunks of data which get sent into some magical cloud, which then passes them to the components. No components calling functions of other components or anything like that. This magical cloud is an execution manager which does have access to the components, but it shouldn’t directly access them either, but rather add the message to a queue. The component should then process it as soon as its ready to do so (the execution manager makes sure that it gets run – or if each component has its own thread, then it will manage itself). Because calling other components only happens through messages, I see no reason that they cannot be sent over a network, or whatever you want to do.
This implementation doesn’t allow you to do these things easily, but my goals with this post were more to introduce the idea and provide some simple code to play with. I think this code is simple enough that people should be able to grasp it right away. I do intend on improving this code, though.
As for dataflow, for the moment I’m treating it seperately from this stuff. Eventually I’ll unify all of the concepts under a single system/language/framework.
Regarding grouping of functions inside components, this is something I had thought about a few years ago, in relation to developing operating systems. The idea was to more-or-less NOT provide any functions – to implement a function, you must implement a message handler. To call a function, you must send a message. I do see this as the way to go, but for a C++ implementation, theres obviosuly nothing stopping you from having each component be a stacked hierarchy of fucntion calls. This has the flaw that theres no obvious means of knowing how much any given component should contain – a flaw which you pointed out, in your blog, that dataflow does not have.
I had this implemented a while back, but unfortunately I lost the code due to a disk failure. This version had a pool of one or more threads, which would process components. Each thread was the exact same and could process the same components. The event manager was responsible for creating events from a memory pool. Events were extremely cheap to construct and destroy, so there were no issues with communicating only over events. The only locking code that was needed was to access the queues onto which components were placed when they had an event to process. Everything else was completely lockless. There was some complex code in there, but overall, it was a pretty simple system. It worked very well and I was planning on turning it into a small game engine. Unfortunately, the disk died and I lost the code. Lesson learnt – always back up code! Oh well, the next version will be much better!
Comment by dublindan — July 25, 2009 @ 9:22 am |
Good to hear (about everything. I especially like the part about converting functions to messages). I was wondering when I was writing my comment how in the world you can start with an example that has all the required features without alienating the reader. That’s why I think your example is a good one. You start by initially separating what needs to be separated and then you can update how the messages get passed and how the execution is handled. Since you had this all in mind to start off (and more), I think a followup article would be better than changing this one. I quite like this one (and the last paragraph of your comment is great! It’s almost impossible to read about implementation details of this kind of execution model).
Comment by Vorlath — July 25, 2009 @ 7:29 pm |