Sign in to follow this  

When to use and not to use singletons

This topic is 3846 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

I am starting to get worried that I may be overusing singletons in my game. What I'm looking for is a little guidance into when to use singletons. I have currently been of the opinion that I should use singletons when I want to enforce the creation of only one object. I am using singletons for:
  • Logging system
  • Script engine
  • Input
  • Renderer
Is this overkill? Obviously there is a little bit (am I right?) of overhead on the ::GetInstance() function call, but nothing that should be a showstopper - correct? Now I could make the input system a member of the kernel...but there should be only one input. I am also the only person who is developing this as well as (most likely)the only person to use the code later on. Modularity is key for my desgin, as I want to be able to redo the engine in version 2 and 3 to support 3D + multi threading. So I need to be looking towards the future (am currently doing 2D - no threading) Any suggestions? Comments? Cheers [Edited by - _Sigma on May 23, 2007 11:46:09 AM]

Share this post


Link to post
Share on other sites
There's no reason any of the subsystems you listed should be singletons.

Quote:

I have currently been of the opinion that I should use singletons when I want to enforce the creation of only one object.

Singletons are for when there must be only one instance and you must provide global access to that instance. None of the subsystems you listed meet either criteria (singletons are not about protecting yourself from yourself or other programmers, which is what you're attempting to do -- "I uwant to enforce the creation of only one object" is not "there must be one only one.").

Quote:

Is this overkill? Obviously there is a little bit (am I right?) of overhead on the ::GetInstance() function call, but nothing that should be a showstopper - correct?

It's not the overhead of the implementation detail that makes singletons bad (in many implementations the overhead can be compiled out entirely).

Quote:

I am also the only person who is developing this as well as (most likely)the only person to use the code later on.

This is not an excuse to write poor code or develop poor designs, unless you are a poor programmer. Don't be a poor programmer.

Quote:

Modularity is key for my design.

Singletons reduce modularity and extensibility.

Okay. Now, I've pretty much come to the conclusion in my years of experience that there is no need, ever, for a singleton. At best I will admit to there being a very-very-very-very-small-but-non-zero percentage of situations that actually warrant a singleton. Here's why:

Consider aspect one of the singleton: "There must be exactly one instance." The "must" is critical, here. Not "we want there to be only one" but "there must be only one." This situation rarely occurs at all, and never occurs in game development (it's usually restricted to very low-level embedded systems or when you're building an interface to some particularly wonky hardware, and in those cases you tend to be using lower-level methodologies for your code anyway). This trait is often twisted from "must be" to "want to be" by programmers, however; this is bad, because this is writing code in an attempt to protect the programmer from himself or other programmers. A truly determined programmer will subvert your protections trivially regardless of what you do; you're just breaking your design and making work more difficult for those programmers who want to use your interface correctly in a vain attempt to protect yourself from the edge case: the programmer will be knowingly doing something stupid.

This is further underscored by the fact that you, in this particular case, claim to be the only developer. You know the proper way to use the interface is (for now) to create only one. So create only one. Don't waste time breaking your design and jumping through hoops to restrict yourself with a restriction you don't really need.

The second issue: "Global access must be provided." It is again rare that global access is to a subsystem is needed in a well-designed API ecosystem. The reason people often perceive global access as required is because their overall design is broken. The Input subsystem is needed only by those parts of the game that process input and translate that input into commands to other underlying subsystems (game logic, rendering, physics, whatever). Similarly for other subsystems. Yes, there will be a common "connection point" where all or most subsystems exist at the same "visibility level" (this is typically in a "game" object somewhere that deals with code and methods specific to the game or project), but global access is not required.

Even logging can be done without the aid of a globally-accessible singleton object, if you think hard enough about it. And none of the other subsystems required singletons, either. Since they don't require them, why limit yourself, especially if you're at all concerned about future directions? Because singletons are such a crutch, they creep all over the codebase, allowing you to take the easy hacky solution (often without even thinking), and making refactoring and maintainability for future modifications a hellish thing.

Unfortunately, since singletons are often a cure-for-a-symptom rather than a cure-for-the-problem (a bad design), it's impossible to give a straight, reusable solution to removing singletons from your code. It depends on the designs in question -- if you provide some more information about the overall architecture of your project and how things intercommunicate, I could provide some specific suggestions.

It boils down to considering lines of communication and interdependency, and removing as many dependency couplings as possible, bubbling them up to higher level subsytems (like the "game" object).

[Edited by - jpetrie on May 23, 2007 11:53:49 AM]

Share this post


Link to post
Share on other sites
Personally, I don't think you should ever use singletons. I really mean that -- there are legitimate uses of goto once in a while, but singletons?

Let us ignore the design errors that would lead you to use a global single instance class. Suppose that for some reason, you want to make those mistakes and nobody is going to stop you. Even then, why would you use a singleton? What exactly is gained over free-floating data (presumably in a namespace) or static data in a dummy class? The only answer I've seen that I'm willing to buy is that the singleton protects volatile/synchronized data, so you need to force a single point of access (this would be the singleton getter).

And if you can tell me with a straight face that you think a design that requires a singly instanced, globally accessible, volatile/synchronized class is not fundamentally broken, then I'm simply going to walk away from the debate.

Share this post


Link to post
Share on other sites
haha. Well I guess that answers that! Looks like I need a redesign...:(

edit:
Quote:
...and you must provide global access to that instance.

Actually, the logging system is the only one I believe falls under that, as it is used in almost all the other classes.

[Edited by - _Sigma on May 23, 2007 11:09:43 AM]

Share this post


Link to post
Share on other sites
Disclaimer: This is all my opinion you may disagree.

You shouldnt use singletons just because you want to enforce the creation of only a single instance but instead when
a) There is no possibility that anyone could ever require more then one instance, i.e. there is a big logical flaw to being able to create more then one instance or
b) The effort required to support the creation of more then one instance (implementation wise) is far greater then the potential pitfalls.

So following a and b above:

Kernel:

Cant really comment because I dont know anything about your design but if its possible to run multiple copies of the game then this shouldnt be a singleton, in particular consider weather supporting multiplayer would require multiple instances of this.

Logging system:

This shouldnt be a singleton because you may require more then one logger and its not hard to concieve of such situations, for example, you want to log graphics related and network related things to different locations.

Script engine:

I think this may validly be a singleton depending on the design, however, I think that this is more due to the difficulty of supporting multiple scripting engines if you havnt designed for it from the start rather then from logically requiring only a single scripting engine, for example if you where to script GUI objects and game characters then you may well want to use more then one scrippting engine so you can dispose of the resources that the scripting engine uses for the GUI once the actual game starts. Basically if your just starting I dont think theres any reason for this to be a singletonn, however, its also one of the ones with the least compelling reasons to change if your working with existing code.

Input:

Input shouldnt be a singleton because multiplayer would require more then one location for recieving input (weather this is from a network or keyboard/mouse). In addition supporting input from multiple locations should require very little effort in comparison to only supporting a single input.

Renderer:

I dont think a renderer should be a singleton because you may require (want to use) multiple renderers to give the players views of different areas of the world particularly in a multi monitor scenario.

Quote:
Is this overkill? Obviously there is a little bit (am I right?) of overhead on the ::GetInstance() function call, but nothing that should be a showstopper - correct?


Depending on the implementation of GetInstance there can be from zero to a very tiny bit of overhead but yes theres nothing that should be a showstopper.

Edit: To slow, jpetrie say's it much better.

Share this post


Link to post
Share on other sites
Quote:
Original post by Promit
And if you can tell me with a straight face that you think a design that requires a singly instanced, globally accessible, volatile/synchronized class is not fundamentally broken, then I'm simply going to walk away from the debate.


I have a design that requires a singly instanced, globally accessible, violatile/synchronized class, which is not fundamentally broken.











It's a design that's designed to serve as an example of what not to do, and it does a fine job of that.

Share this post


Link to post
Share on other sites
Thanks for the long replies - answers a lot of questions!

Quick note - kernel is not actually a singleton sorry!

This is my current design (now without singletons - only change is that they used to be singletons :S - Please don't hurt me!!! O_o lol). The following diagram does not show inheritence, rather just how
objects are in relation to one another. ie, a TScript instance is a member of TKernel




TKernel TLog (global singleton)
|
+----------+----------+
| | |
TScript TInput TRender



The kernel holds a main() that is called into from WinMain. Here we make the calls to handle the
windows messages before handling our own.

Once done, there is a ScriptMain() function in the script that does all the high level work, such as
adding things to the render queue(ie: Draw(player) ), moving monsters, etc. Other funtions in the script can be registered
to be called on input, so


void OnKeyLeftDown()
{
player.moveLeft(10); //10pixels left
}

and input would then, upon detecting a key down, check if there is a function associated with this action, and if so, call it.

On return to the kernel.main() (ie, exiting the script main), we do all the grunt work , such as
the actual rendering, the AI, pathfinding, etc.

On the next iteration, call back into the script main function, and repeat.

Is this enough information? I'm currently still fleshing out some design ideas, so not everything has been written down yet!

Thinking this through, everyone's advice on not using all those singleton's seems to make a lot of sense. I think I was caught up
playing with something new!

At the moment, TKernel really is the top object, and everything below it doesn't need to know about the others.

THe only interface a user gets is what ends up being exposed to the scripting language (Angle Script in this case)

Cheers
Chris

Share this post


Link to post
Share on other sites
Quote:
Script engine:

I think this may validly be a singleton depending on the design, however, I think that this is more due to the difficulty of supporting multiple scripting engines if you haven't designed for it from the start rather then from logically requiring only a single scripting engine, for example if you where to script GUI objects and game characters then you may well want to use more then one scrippting engine so you can dispose of the resources that the scripting engine uses for the GUI once the actual game starts. Basically if your just starting I dont think theres any reason for this to be a singletonn, however, its also one of the ones with the least compelling reasons to change if your working with existing code.


Currently only one script engine is supported, and I think actually warranted.

I'm actually at a bit of a undecided point regarding how I want to full implement this. I am just implementing the basic parts to get a feel for what
can be easily done with AS, before full sorting out what I want to do.

Eventually, I would like each level to be fully scripted with events that are triggered depending on global events (in the game world).
Since you can have AS compile scripts into different namespaces, I originally thought to separate AI from Input. But then it became difficult
to keep track of which namespace (module) each function was in, so I just now have all scripts compiled into the same module.

Currently, I envision this being done like thus:

- each .map file contains
= all the art assets for the map
= tile maps
= script file(s)
= etc...

The tile map would then have references to a script function if we wanted to process a scripted event.

As well, AS allows for using the include directive, so if you want to reuse code this is easy, and allows for communication among script files.

So if (and this is really down the line) I wanted to script GUIs, I think I would just compile into a separate module instead of a new
engine...

Share this post


Link to post
Share on other sites
I find having a logger object as simply a global is a good tradeoff between ease of use and design (read: I'm lazy).

Converting std::cout/cerr/clog to being such a logger is much easier than I thought, thanks to this post by Bregma. I have cut down his sample code to bare bones and built a class that will output to a number of "log streams", for example a single call to std::cout will write to a log file and a message to my in game console. Simple enough and works quite well.

Share this post


Link to post
Share on other sites
Once you strip out the singletons, the system you're proposing is not that bad. The scripting layer provides the connective tissue between the game-specific logic and the renderer and other subsystems without coupling them too tightly, allowing those other subsystems to be reused with relative ease.

I still don't see a need to make the scripting layer a singleton, however. Right now there might be one, but in the future it might benefit you to be able to spawn multiple (for example, perhaps, depending on your implementation, another scripting instance could be used to play back previous gamestate concurrent with another running gamestate to provide replay features or something). A singleton would make assumptions that might tie your hands in the future, here.

I usually get around the global issue for logging subsystems by making either free functions or scoped logging objects (stack instances, created with a macro in C++ so I can automatically embed some file/line/function info, that accumulate log messages and dump them immediately or in the destructor). Free functions also work, although in languages that don't permit them (C#) you end up with static classes which, if you're not careful, can effectively become singletons.

Share this post


Link to post
Share on other sites
Sigma, are you considering the factory pattern? Im not so sure it sounds like you are really using singletons?

Also since there has been such a dislike for singletons, what does every1 think about factory patterns? I for one use something a bit like sigma from what it sounds where I have a main engine if u will that contains or can contain different sub-engines.

For instance I have an object type factory where different objects(renderable game objects) are put into and then created upon what they really are. Once in it searches for that object's correct mesh(which other objects can use) amongst other things. Once rendering time comes, a single object could be rendered or it can be queued up for managed rendering which allows for the least amount of states to be changed through all objects. I could make this a Singleton class but in reality it doesnt NEED to be. It really acts more of a factory.

It all depends on which ones require which events. Speaking of that - my event handler doesnt need 2 of it either at this point. But it could if needed.

Sigma, is this the kind of design you have? If so, to others - is this a bad design then?

Share this post


Link to post
Share on other sites
As a design pattern, factories are much less abused than singletons, but they still can be. For example, the vague description you provided suggests that you might have a factory responsible for creating all types of objects -- things that are renderable, things that are game logic, et cetera. That's bad, because it does not appropriate separate responsibility across logical subsystem boundaries.

But I'm rather confused by your description of "sub-engines" and objects being "put into the factory and then created based on what they are," so maybe I'm misunderstanding the rest of your presentation.

Fundamentally, a factory is about constructing specific concrete instances from a family of types identified by a particular value of a key type that is runtime-determined (as opposed to compile-time-determined, in which case the factory is probably unnecessary).

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
For example, the vague description you provided suggests that you might have a factory responsible for creating all types of objects -- things that are renderable, things that are game logic, et cetera. That's bad, because it does not appropriate separate responsibility across logical subsystem boundaries.

But I'm rather confused by your description of "sub-engines" and objects being "put into the factory and then created based on what they are," so maybe I'm misunderstanding the rest of your presentation.


Well imagine 3D objects, taken in from a file. Those objects could use the same Mesh, could need the same shaders applied, could use the same textures, and so on.
By creating them correctly im making sure that the objects are in correct standing and are also not creating multiple resources of the same item.

Instead of creating multiple instances everywhere I have a factory that holds them and manages what is passed out. It can also render them efficiently if need be based on there characteristics, less state changing is an example. I found it was much easier to allow for this to be in one place rather than all over, which can happen if a programmer really wanted it. Yet it would seem easier to have a programmer simply extend the factory into what they wanted.

The object factory was just an example, I should have said 3DObject factory but its not limited to 3D objects but renderable objects. Game states, input, and so on are in other places, not in the object factory.

Again the reason I went with this design was for rendering efficiency. Also note the Object factory does not manage the meshs or shaders, but can create them if needed in their correct place by event messaging.

also
Quote:
Original post by jpetrie
That's bad, because it does not appropriate separate responsibility across logical subsystem boundaries.


could you elaborate more on this for me?

Share this post


Link to post
Share on other sites
Quote:

Instead of creating multiple instances everywhere I have a factory that holds them and manages what is passed out.

This system you describe is not a factory. It's more of a caching system - there may be two instances of the Goblin in a level and fourteen Lava Monsters, but you'll only need to store one copy of the Goblin geometry and one copy of the Lava Monster geometry, and simply reference that cached geometry from each particular instance. It's a good, common, general methodology, but calling it a factory is a misnomer.

Quote:

The object factory was just an example, I should have said 3DObject factory but its not limited to 3D objects but renderable objects. Game states, input, and so on are in other places, not in the object factory.

Good, game states don't belong in the same place as your renderable object cache.

Quote:

could you elaborate more on this for me?

Separating responsibility improves maintainability and extensibility of your code; thus the Single Responsibility Principal, which stipulates that a particular class should have one and only one responsibility and not become bogged down by doing many different unrelated things (typical "manager" classes for example).

Separating subsystems reduces coupling and dependencies, which also increase maintainability and extensibility. Consider the renderable object cache you have (again, it's not a factory). It's a geometry cache used by the rendering subsystem to prevent unnecessary duplication of resources (mesh data). Now, if you put other types of data in this very same cache (for example, audio data, or physics information, or game states, or whatever), now you've violated the above two principals: the cache is now responsible for managing multiple completely unrelated types of data (which might require different management patterns, such as how to cache them and when to expunge them from the cache, if at all), and the cache crosses subsystem boundaries (its used by the renderer, and the audio system, and the physics system...) which means it is now dependent on those subsystems and those subsystems are dependent on it. Which in turns means all subsystems depend indirectly on each other, which means they cannot be reused independantly of each other. A bad design overall.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
It's a good, common, general methodology, but calling it a factory is a misnomer.


Ahh well looks like I need to read up on what a caching system, factory, and manager really are. I think somewhere down the line they blurred for me, I was under different assumptions it appears.

Share this post


Link to post
Share on other sites
Quote:
Quote:
Original post by xsirxx
It's a good, common, general methodology, but calling it a factory is a misnomer.
Ahh well looks like I need to read up on what a caching system, factory, and manager really are. I think somewhere down the line they blurred for me, I was under different assumptions it appears.
There's been significant discussion in the past about the use of the term 'manager', because basically, the word doesn't mean much when applied to a class. The discussion is probably worth reading.

Share this post


Link to post
Share on other sites
No.

There's no reason to restrict yourself to a single instance of the engine (if you only want one, only make one), nor is there any reason to allow global access to a root "engine" object itself, because that allows dependency creed to pollute the code and render it brittle.

(See also the other active singleton thread for elaboration.)

Share this post


Link to post
Share on other sites
Wow...

I had no idea singletons were such a hot topic!

jpetrie,Promit, you're bringing me to your side. Although you've yet to convince me on the Logger class not being a singleton!<BG>

Quote:

Sigma, are you considering the factory pattern?
Negatorial my friend.
Quote:
Once you strip out the singletons, the system you're proposing is not that bad...I still don't see a need to make the scripting layer a singleton, however.

I rewrote the small portion of TScript so it is no longer a singleton.
Do you have any other suggestions or do you need more information?

The only singleton left is the logger, which I'm not changing! =)

Cheers

Share this post


Link to post
Share on other sites
Quote:
Original post by _Sigma
Although you've yet to convince me on the Logger class not being a singleton!


Suppose you want to filter information into multiple categories. Seems reasonable enough -- say your AI system locks up due to an internal mutex deadlock. You'd rather be able to skip to the end of the AI log to figure out when it occurred, rather than spend your time searching for the last AI log entry in your entire log history.

Now, we know multithreaded situations can be a pain in the ass to reproduce -- the slightest timing can change when the problem occurs immensely. So what happens when the AI system locks up because of some external event, but everything else kept running? Well now we need the other logs.

Okay. Multiple information categories, multiple destinations. How do we do this in a singleton? I suppose we could use a bunch of flags. One for each subsystem category, you know? But what happens when you start having problems in subsubsystems of your main systems? Replacing flags all day long throughout specific parts of your code sounds tedious to do all day long.

OK OK, I know: We'll store the flag to use in a variable -- each system passes their flag down to it's own subsystems by default, and if we ever need to give a sub(sub(sub(sub....)))system it's own category, we can just replace it where that system is initialized. Piece of cake, right?

Here, we can make it even easier. Since we're always using the same variable that was passed down to use, lets put it in a wrapper. We can call it LogUser. It has a function, Log(), which calls OurSingletonLogger::Instance()->Log( this->category, ... ); or whatever on our behalf, saving on typing. We've simply replaced singleton->Log( category , ... ) with loguser->Log( ... ).

Okay, now one of our game servers is crashing that I don't want to hook a monitor up to. Or maybe we're causing a BSOD somehow which is discarding our most recent writes to our log, since although they've been flushed to the OS, the OS hadn't written them to disk before the BSOD. Okay, okay, we can send them over the network. Time to add more logic so we can do this instead of to-file logging.

Hmm. Say, you know, adding this to those big conditional statements in OurSingletonLogger sounds tedious. We've got most of our code just using LogUsers -- let's put doing that off until we need to. Let's just have NetworkLogUser log directly to network -- we've been passing them around by reference anyways for the most part, right? We can cause making a LogUser from a NetworkLogUser to be a compile error if we need to find any old code that could be a problem.


Hmm. You know, NetworkLogger is more descriptive of this class than NetworkLogUser. What was it that OurSingletonLogger did again?

Oh, right, it filtered information by flag. Which we got tired of replacing throughout our code, so we made it a variable that cascaded through the system heiarchy by default, which we then wrapped, which ended up containing all the logic for 1 specific logging destination inside of itself instead of inside a big dispatch conditional in OurSingletonLogger.

Oh snap, gentlemen! Does OurSingletonLogger still serve a purpose? All the information is already filtered by way of selecting multiple LogUsers for now.

I can't think of one. Can you?









We happen to be looking at a pattern known as dependency injection here, by the way. See this page of mine for a less convoluted C++ example, this time replacing usage of a std::cout for logging with a std::ostream&, allowing different WebServers to easily share logs, use separate logs, or use new log types (for unit testing no less!)

Portland Pattern Repository on Dependency Injection (oddly, this just has a general terminology overview in place there currently)

[Edited by - MaulingMonkey on May 24, 2007 1:00:59 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Promit
Personally, I don't think you should ever use singletons. I really mean that -- there are legitimate uses of goto once in a while, but singletons?


Ever use XNA?

Share this post


Link to post
Share on other sites
Quote:
Original post by skittleo
Quote:
Original post by Promit
Personally, I don't think you should ever use singletons. I really mean that -- there are legitimate uses of goto once in a while, but singletons?


Ever use XNA?


i'm using xna, still i haven't had any need to implement a singleton... or do you mean certain things there, like mouse or keyboard, are a singleton? well, this is understandable, based on the knowledge of the os limitations. but it shouldn't be, so we could play with several mice at the same time, or keyboards, just as an idea that singletons at every state in a system only limit in one way, or another.

Share this post


Link to post
Share on other sites
Quote:
Original post by skittleo
Quote:
Original post by Promit
Personally, I don't think you should ever use singletons. I really mean that -- there are legitimate uses of goto once in a while, but singletons?


Ever use XNA?
What about it?

Share this post


Link to post
Share on other sites

This topic is 3846 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