Singletons: Globals by Any Other Name…


… are still globals.

Or, more specifically, singletons are global variables.  Really, that statement shouldn’t surprise anyone.  But, every once in a while, usually in the middle of designing or researching code templates for creating singletons, people can forget what the singleton pattern was actually designed to accomplish.

For most intents and purposes, there is no real difference between:

gGraphicsDevice->Draw(something);

 
and

GraphicsDevice::GetInstance()->Draw(something);

The singleton code is no safer or more performant than the global variable code. In fact, depending on what your singleton does, it’s probably more expensive than a plain global variable access.

The singleton pattern is designed to solve one problem. It exists to prevent the creation of multiple instances of something for which there should only ever be one instance. There are plenty of examples of entities in game development that are generally singleton in nature: graphic cards, file managers, memory managers, and the like. Be that as it may, that doesn’t mean they necessarily benefit from the singleton pattern.

Most “singleton” entities don’t actually benefit from the singleton pattern because the primary function of the pattern is to prevent multiple instantiation of a particular object. Now, ask yourself: In real-life development, how often has this actually been a problem?

Barring complete ignorance / idiocy, no programmer in their right mind would think to write:

void SomeObject::Update(float deltaSeconds)
{
   FileManager* pMyFileManager = new FileManager;
   pMyFileManager->DoSomething();
   delete pMyFileManager;
}

Any sane programmer in almost any development environment would expect something like a file manager to already have been instantiated elsewhere in the code and would just need to know how they should access it. (It IS possible to make the code above work as a singleton by using the monostate pattern; but would you really want to encourage such liberal memory allocation/deallocation in your game?) If you happen to have programmers on your team who don’t know how use your engine’s file or memory managers should be accessed then you probably have much deeper communication issues in your team and the singleton pattern certainly won’t solve them.

I did once have someone suggest that a good singleton implementation can serve as a base for implementing thread-safety in your globally shared systems. While this is a nice and romantic OOP sentiment with which I can sympathize, it is unfortunately incorrect. It’s certainly possible to implement some sort of mutex in the accessors for your singleton, but this only protects the time during which someone is getting a pointer to the singleton and doesn’t protect functions being called using that pointer. Implementing a system where the user has to explicitly attain then release a thread-safe pointer to the singleton instance is also possible, but it tends to be easy for a programmer to forget to release a thread-safe programmer and screw things up for other parts of the engine. If you’re going to make your engine multi-threaded, your singleton class is not going to be the place to do it.

Thinking cynically, one of the main unspoken motivations for implementing singelton classes may be to disguise the syntax of global variable usage. Peperring code with global variables gets a bad rap, often with good reason. However, it has also lead a lot of programmers to having the dogmatic belief that global variables have no place in production code or that their usage indicates lack of programming skill or knowledge. While I certainly agree that overuse of global variables is dangerous, there are some systems in a program that will be legitimately globally accessible. In many of these cases, representing these systems with singleton classes may stem less from the need to make sure they are singular than from the desire to shut up anyone who has an aversion to variable names that begin with a Hungarian-notation “g”.

In my opinion, there aren’t a lot of cases in which its worthwhile to implement a singleton class / template. But, just in case, here’s my quick guide for when you MIGHT want to implement one:

  1. You need to guarantee a single (shared) instance of an object AND you can’t trust the users of your code to not instantiate their own copies.
  2. You want to instantiate the global shared instance of your object lazily (i.e. instantiate it on first access) and don’t mind if it might be reinstantiated after disinstantiation.
  3. You need to disguise the use of global variables in your code in order to pass a style guide audit or static analysis checks on your codebase.
Share this Article:
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Print