Singletons in a component based architecture.

Started by
8 comments, last by LorenzoGatti 10 years, 4 months ago

Hello,

So I wanted to write a game using a component based architecture for the obvious reasons of wanting quick iteration and such, thats not my point tough.

What I have thought up is a system were components are implemented in Lua instead of c++, and then Lua can call functions that are implemented in c++. All fine and dandy, however I see a problem.

From the c++ point of view most of my code is just going to be a list Lua functions implemented in c++, with no need for inheritance or things such as that.

Furthermore, if I just put all these Lua functions in classes, as merely namespaces, I will have code, from the c++ point of view thats just a bunch of singletons, with Lua functions in them.

This goes against what I know to be good practice in c++ OOP programming. So my question is, everyone talks about the components and data, but what about the rest of the code, is there a way that all this functionality is normally implemented, as in the functionality for components to use?

Advertisement

You seem to be overthinking things.

It is possible to do OOP in C withtout using classes. You have a struct contains all the data, and you have functions which operate on that struct. There is a tight binding between the functions and the data even though they're separate elements in the code. C++ classes are just shorthand for this. Every time you call a C++ function, you're sending a pointer to a struct as the first parameter. I'm assuming this is basically what you're doing when you call into lua - passing a block of data for the lua script to operate on.

Keep in mind the defining characteristic of a singleton is that it only operates on a single set of data, or in other words, there can only be one instance of the data.

Just make free functions in your C++ code, ideally in a namespace that represents that they are bound to Lua. Problem solved.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


I'm assuming this is basically what you're doing when you call into lua - passing a block of data for the lua script to operate on.

Not quite, most of the code looks like this:


int SetPosition(lua_State* L) {
    int entity = (int)lua_tointeger(L, 1);
    double X = lua_tonumber(L, 2);
    double Y = lua_tonumber(L, 3);

    currentLevel.GetEntity(entity)->trans.SetPosition(Vector2((float)X, (float)Y));

    return 0;
}

This function can be called from Lua, and most of the code is functions like this, that are called from a single Lua state. Currently there is only one Lua state, and so all the functions work of the single Lua state, like a singleton.

No.

A "singleton" does not mean that you only bothered to create one of them. To be a singleton, the code must enforce that there will always be exactly one of them.

The fact that you can pass any lua_State you want into your functions means that you could easily create two, zero, or four thousand lua_states and use all of them (or none of them) freely. This is the exact opposite of what a singleton is meant to accomplish.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


The fact that you can pass any lua_State you want into your functions means that you could easily create two, zero, or four thousand lua_states and use all of them (or none of them) freely. This is the exact opposite of what a singleton is meant to accomplish.

Ok well this is good. So its not the end of the world to just drop in a bunch of free functions organised in namespaces? I shall proceed doing that then.

If it is the case that its not the end of the world I'd like to add why I thought it might be. I often come across experience c++ and OOP programmers who preach using classes and OOP and using all the features of the language. I thought maybe there might be a better way to go about it than just using free functions, or functions wrapped in a class instead of a namespace.


The fact that you can pass any lua_State you want into your functions means that you could easily create two, zero, or four thousand lua_states and use all of them (or none of them) freely. This is the exact opposite of what a singleton is meant to accomplish.

Ok well this is good. So its not the end of the world to just drop in a bunch of free functions organised in namespaces? I shall proceed doing that then.

If it is the case that its not the end of the world I'd like to add why I thought it might be. I often come across experience c++ and OOP programmers who preach using classes and OOP and using all the features of the language. I thought maybe there might be a better way to go about it than just using free functions, or functions wrapped in a class instead of a namespace.

Attempting to shoehorn everything into an OOP model is a mindset from the late 90s/early 00s.

The truth is that OOP should be another tool in your box. It's useful a lot of the time, but it's not for everything.


currentLevel.GetEntity(entity)->trans.SetPosition(Vector2((float)X, (float)Y));

Where does currentLevel come from? Is it a global variable?


Where does currentLevel come from? Is it a global variable?

Yes, yes it is. One of the very few in fact.

So its not the end of the world to just drop in a bunch of free functions organised in namespaces? I shall proceed doing that then.

It's the standard and best way to do it, not merely good enough.
C++ has three places for functions: top-level; inside a class (or a struct or union); or inside a namespace. A class is unsuitable because it implies defining a data type but you have "a bunch of free functions", while namespaces offer additional features you might find useful, like nesting (allowing all sorts of classifications, not only a single level) and support for distributing declarations across different compilation units without a pointless central "directory" of your Lua-callable functions (as a class would be).

Omae Wa Mou Shindeiru

This topic is closed to new replies.

Advertisement