Yes, you can get rid of things by including a null pointer, which is about a quarter the size of a typical tier in my system, not to mention I have no idea how that would come to behave, as I'm not sure I can tell what an implementation of draw_sprite would look like nor where it would be located. Would you mind showing me that?
Either way, it's not that it's just difficult to get rid of everything; it's difficult to add things, too. With the tier system, all I need to know is the name of the bottom tier.
I've given your component system so much thought that I literally spent the night dreaming about it and rolling over every hour as a consequence. I see that the beautiful thing about this system is that the components can be swapped out just by passing a pointer different child component to the structure. That's great. Not for here. I vastly prefer to just include the appropriate header and link the appropriate source from a well-organized system of folders.
An argument that keeps popping up is the ability to change out systems at run time. That's catastrophic. Let's look at what systems we can actually exchange...
Collision system | Any motivation to change this out would result from the speed increase. This should vary only proportionally from system to system; changing out the system at run time would be of no benefit. |
Graphics systems | This seems useful at first, but the only platform to which this applies is Windows. Every other platform only offers one system. And on Windows, it is safe to assume that DirectX vastly outperforms GL, because that's what lazy cardmakers invest in (think Intel). On Windows, DirectX would always be the choice for speed; GL would be offered mostly for people whose philosophy forbids DX. |
Sound System | Same case as graphics. |
Window System | Each platform has only one at the moment; I chose to code each natively because that would likely be the fastest method. This is the most fundamental change between platforms. |
Debug System | Much of ENIGMA is based on the thought that debugging should be done -prior- to release. I can't think of a good reason to put debug information for my game at the hands of its users; people got pretty pissed about GM's debug mode being invocable at the flip of a bit. |
Now, that table is on a per-OS basis; it doesn't account for the benefits when moving platforms. This is because you can't move a C++ module from platform to platform, end of story.
Feel free, of course, to point out some benefit I've missed; your best bet is to show how a run-time plug-and-play debug mode would be useful.
I can't see how a debugger component would help me at all; I have sovereign control over the types of every variable. I can replace all local variables from "type varname;" to "debug_proxy<type> varname;", and I can do it without any effort at all. I never once felt the need for a system such as this to help me.
Further, I don't understand what could be added to the functions of a component to help with debugging. Users are supposed to be able to assume that the functions in ENIGMA behave as they say they will. If they don't, that's my problem, and I know how to work GDB.
And yes, you've again named more vague things that I can do with this system but will probably never want/need to do. Show me an instance in which you, the advocate of this method, would find reusable behaviors useful. Further, as I've been hinting at, dependency resolution isn't simpler with components. In fact, it seems far more difficult. The tier system lets my parser figure out what all the implemented locals are based only on the name of the top tier. I can't think of a method of determining the contents of your components without being told, and it seems that you can't, either. You yourself mentioned earlier that the "whole system will be implemented with them in mind;" this is contrary to the point you're trying to make about components--that they are more modular and have less dependencies requiring recompilation.
In fact, your system suffers the same problems as my old system, before tiers; it has to either include the end result of the system (being the definition of struct Object) before it can make use of its members--meaning that it needs basic definitions of each (if only your small parent classes)--, or you can work around knowing the entirety of Object by passing, say, RasterSprite to Colligma via its constructor, as it seems you've done. This is remarkably similar to what is happening with the tiers. It comes down to the difference being that you can pass something other than RasterSprite, or a modified RasterSprite, to Colligma without relying on the preprocessor, which I love and you hate.
But, just like in my tier system, if you want to edit the RasterSprite component, the Colligma component needs recompiled; editing a component will produce the same amount of recompilation as editing a tier in my current system. It's
extending a component that yours can do without recompiling everything (the extension being done itself tiering, I might add). Even then, you still need to recompile the main source, because now the available locals have changed and the wrong component will be allocated otherwise, (you'll get the shorter RasterSprite than you ultimately ended up using), leading to misbehavior (in the form of calling the short function if all the code is stored in the components as you are suggesting, or a segfault otherwise).
With this system, I just include the highest tier I need in each source, and then include the correct set of sources for the system I want.
Also, ENIGMA is not supposed to be
just a GM clone; that's why it implements a number of functions that GM Does not, in addition to the entirety of the C/C++ libraries. What more do you want, other than pointers everywhere, which makes life no easier for the users, much harder for me, and only possibly easier for future developers, which are apparently mythological creatures.