Sign in to follow this  

Class registration mechanism (Now: Singleton: good or bad?)

This topic is 3487 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Oh no, not another Singleton thread!!! Hi! I have exactly one singleton in my engine and I would very much like to get rid of it. The problem is, that it's just so darn convenient ;-) I have an extensible Entity-System that is built around an EnityFactory class which is currently a singleton. Through the use of the following macro magic, each entity class registers with the EntityFactory, and it does so more or less "automatically":
#define RegisterEntityClass(entityClass) static bool   entity##entityClass##__LINE__ =   EntityFactory::GetDefaultFactory()->   RegisterClass(#entityClass,   &EntityFactory::FactoryMethod<entityClass>)

class MyCustomEntity : public Entity
{
...
};

RegisterEntityClass(MyCustomEntity);

EntityFactory* factory = EntityFactory::GetDefaultFactory();
Handle<MyCustomEntity> myEntity = factory ->Create<MyCustomEntity>(L"MyCustomEntity", L"id");


I'm using a singleton and not just a class with static member functions to avoid the "static initialization order fiasco". So here's the thing: apart from the EntityFactory class, my engine is 100% singleton free(TM) and I'm not really comfortable with EntityFactory being a singleton. I tried to hide the fact that it's a singleton by calling the singleton method "GetDefaultFactory" and making the constructor public (so in theory you could create more than one EntityFactory), but that's mostly for show. So I'm looking for ideas on how to get rid of the Singleton without losing too much of the convenience of this system. Cheers and thanks! [Edited by - Harry Hunt on May 26, 2008 1:48:26 PM]

Share this post


Link to post
Share on other sites
You can't, unless you explicitly register all the classes during some initialization process.

In your case, you do need a global point that any piece of code can access. And, because you don't define proper initialization order, you need to guarantee that there is only one of those, so that all classes register with exactly same one.

In your case, you really do need a globally accessible instance, which must be the same for all. Having two would break the system, since classes would register with either one.

Share this post


Link to post
Share on other sites
This is the pain of using singletons from the get go. They bite you in the butt later on when you figure out they're useless (There is that 1% when you have a physical hardware limitation that needs one, then again just make one ;-) ). Refactoring this late can be a real pain, I don't envy you at all. Best of luck.

Share this post


Link to post
Share on other sites
Quote:
Original post by Harry Hunt
I have exactly one singleton in my engine and I would very much like to get rid of it. The problem is, that it's just so darn convenient ;-)
I hardly believe it! ;-)
Quote:
Original post by Harry Hunt
I have an extensible Entity-System that is built around an EnityFactory class which is currently a singleton. Through the use of the following macro magic, each entity class registers with the EntityFactory, and it does so more or less "automatically":
Don't do this. Macros are outside standard rules. They will likely bite you where it hurts sooner or later. Macros are BAD, sometimes magic, use them with care.
Quote:
Original post by Harry Hunt
I'm using a singleton and not just a class with static member functions to avoid the "static initialization order fiasco".
Go for class. Having a this pointer to mess with always comes useful in the long run.
EXAMPLE:
NewLoadQuery(ResourceResolver &resolver, String &resourceName)

Have "phun" in passing a static object down this road. Think you don't need it? Think well.
Quote:
Original post by Harry Hunt
So here's the thing: apart from the EntityFactory class, my engine is 100% singleton free(TM) and I'm not really comfortable with EntityFactory being a singleton. I tried to hide the fact that it's a singleton by calling the singleton method "GetDefaultFactory" and making the constructor public (so in theory you could create more than one EntityFactory), but that's mostly for show.
I'm not yet sure of what this "EntityFactory" is meant to do.

Share this post


Link to post
Share on other sites
Thanks for the replies!

The whole point of the entity factory is that I can create new entity classes in the game DLL and they will immediately show up in the map editor, without me writing any additional code. It also allows me to serialize entities using a unified interface and then re-instantiate them using just the class name.
In a way, this is a homegrown replacement for real introspection. In Java, you have Class.forName() and this is my version of it if you will.

Of course it doesn't have to be a singleton and it most likely won't be in the future, but initially this seemed like a natural choice.

Quote:
I hardly believe it! ;-)


It's true. Whenever I felt compelled to use a singleton, I spent some time thinking about it and always came up with a better solution (with the exception of the entity factory).

Quote:
Don't do this. Macros are outside standard rules.


I agree, macros are evil and that's one reason why I don't like my current solution.

Quote:
If the singleton works and is convenient, why do you want to get rid of it?


Good question. I guess I simply don't like singletons and I need to prove to myself that I can live without them ;-)

Share this post


Link to post
Share on other sites
Quote:
Original post by Hnefi
If the singleton works and is convenient, why do you want to get rid of it?


This is exactly my mantra. People say its bad design, but I say its bad decision making. A singleton is a tool, much like a hammer, that does a specific job. You wouldn't use a hammer in places that do not need hammering, such as tightening a bolt. I believe this is where people run into problems with it. For example, I use singletons in my engine. One class that I have that uses it is called my EventManager class. It funnels and directs events to all portions of the system. It is coupled to other parts of the system via interfaces, not by classes themselves. Other classes that choose to send and receive events would have to include the eventSystem regardless if it was a singleton. I think this is a great example of when to use one, especially on a class that does not depend on memory management order.

In other places, such as window class, a singleton seems counter productive because your engine would only support having one window. In this case I would not use a singleton, rather I would register that window with my EventManager and let it route events to it as they come.

Also, if designed correctly, a singleton class can become a regular dynamic class with very little change. For example, I have a ResourceManager class, that manages a resource pool. Currently its a singleton class because I assumed that people would only want one of these classes. After careful research, I found that people may need more then one. So, I just took out the getInstance() function and made the constructor public. Now the user is faced with registering all resource-related objects manually, rather then automatically by the interfaces that make the resourceManager work.

So, in the end, a singleton is a tool that, if used properly, has the potential of clearing up code, but if used badly, can make refactoring a nightmare.

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
This is exactly my mantra. People say its bad design, but I say its bad decision making. A singleton is a tool, much like a hammer, that does a specific job.
A singleton is a tool, like an oil filter wrench, that does a specific job. A lot of people, for various reasons, have decided to use this oil filter wrench to hammer everything in sight. Even if you take "hammer everything in sight" as a reasonable construction technique, using an oil filter wrench for it is sort of a stupid idea.

If you want global variables, you know where to get them.

Share this post


Link to post
Share on other sites
Quote:
So, in the end, a singleton is a tool that, if used properly, has the potential of clearing up code, but if used badly, can make refactoring a nightmare.


How exactly does it clear up code? It actually pollutes it I find. Hunting down bugs becomes much harder. Your basically disguising a global as something else. If you need a global use it. Just be aware of it's downsides. If you need just one instance, make just once instance. Unless you have a physical requirement (hardware) then a singleton is most likely not the right hammer for the job.

Share this post


Link to post
Share on other sites
Oh noes, what have I done!

This wasn't meant to become yet another "Singleton good or bad" thread. I'm already convinced that singletons are a poor choice in 99.9% of all cases. Thank you very much...

So move on people, nothing to see here ;-)

I'm kidding of course. Just don't turn this into a flame war pleeeze...

Share this post


Link to post
Share on other sites
As a slight aside, this sort of thing would be moot if C++ provided any sort of reflection capability. As it is, I would tend toward some explicit external pre-build tool to generate an "InitializeEntityFactory()" function from your class definitions.

Easier to debug than macros, easier to deal with at runtime, mildly more difficult to implement.

Share this post


Link to post
Share on other sites
Quote:
Original post by Harry Hunt
It's true. Whenever I felt compelled to use a singleton, I spent some time thinking about it and always came up with a better solution (with the exception of the entity factory).
Sorry, there was some irony intended. My fault really. I have rewritten basically everything and I'm now pretty scared by this.

Actually, I have a specific subclass which can be instantiated only once - it has exclusive access to several unique systemwide components. It's a bit weird since this class is not really used in any subsystem - its superclasses are sufficient. It is not even a global variable - it's stack-allocated in main() and passed around.
Why I like this? The main reason is that the functionality needed by each subsystem is well defined and can be refined going down in the processing pipe.

Back in time, when I tried to use a static object (the complexity was much lower and it seemed viable) I had several issues in thinking the relationships as the function and variable count kept growing and the lack of overriding facilities forced me to bad habits.

But came to your point...
Quote:
Original post by Harry Hunt
So I'm looking for ideas on how to get rid of the Singleton without losing too much of the convenience of this system.
Why cannot you just have an Init() call? Am I understanding the problem?
Sure, one would like to have an object ready to go after creation... unluckly, this is not always possible, especially when hardware pokes in.

Share this post


Link to post
Share on other sites

This topic is 3487 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this