So, singletons are evil; what to do then?

I believe we all memorized that the singleton is evil. We all repeat how wrong it is to use singletons in a project, we all repeat we should avoid them or at least keep their usage at minimum. But, I have rarely come across any developers knowing what are the real reasons making singletons evil.

I know in general singleton pattern (or anti pattern according to some software engineers) is problematic, because the singletons are complicated global objects in disguise, and “global variables/objects can give you a real headache” is CS101. But, is that all?

I have had some questions in my mind for sometime already, but (not surprisingly) it took a while for me to make a detailed search. I actually stopped postponing it when I had to make a design decision for the event-driven component I have been working on for a while.

This event-driven component I mentioned is composed of some system events, such as input (mouse, touch, keyboard, etc.), UI, and so on. It also lets you to create some user-defined events meeting your needs. Therefore, I need to have this component globally available, so the classes needing to receive or push events can reach it.

First thing come to my mind was making all the event managers singleton. But, we are talking about at least five event managers, plus with this approach I would also force any user-defined event managers to become singleton as well. Yeah, I can feel the nausea and panic in you. This is trouble.

How about sending references of the related event managers to the related classes that will use the managers (hint to dependency injection (DI) )? But, I also do not feel comfortable by sending several different manager references to some objects that I will have thousands of them in my scene.

What about having a class keeping all the event managers and providing some services that I can reach and use them (hint to service locator design pattern)? But, how will I access this locator? Is it going to be a global variable? A singleton?

These are the questions I faced in the first place, and the more I investigate the more questions appeared. But first, let us know our enemy; singleton pattern.

What is this singleton pattern anyway?

The whole idea behind the singleton is ensuring that the class has one instance, and providing a global point of access to it. That’s why when it comes to managers of any kinds, the singleton is the first pattern comes to mind.

Singleton classes are initialized at run time at the first access. This “first access” does not necessarily mean the access of the first client (This is actually an approach called lazy initialization.), it can be a class or function/method that configure the whole software. Most commonly, singletons don’t take any parameters for creating the instance, but it is not a dogma, of course.

A singleton class has a single, private, parameterless constructor. The idea behind this is enforcing the single instance (If no one can access your constructor, no one can initialize you except yourself). Private constructor also prevents subclassing (so, the singleton classes are sealed/final), which would violate the pattern since each of those subclasses would create an instance. A static variable holds a reference to the single created instance and a public static getter lets you to get this instance.

So, here is the most naive singleton class, written in C#, that you think twice before using it:

Now, we know our enemy, but why is it our enemy?

Why is singleton evil?

The biggest problem of singleton pattern is related with getting lost in the power of global access. If you do not use this power wisely and carefully, it can easily destroy the encapsulation and decoupling of your code. And these are the two key concepts for a good software and software design.

So, usually ask yourself whether you really need to make the class singleton, reconsider your design from a different perspective. For example, if it is only about making the class a single instance, not globally accessible, there are some other ways to make it. Maybe you can pass the instance of this class you consider to make a singleton as a parameter (not in the sense of dependency injection). Even in some rendering systems, the renderer is sent as a parameter instead of turning it into a singleton. Or maybe you can actually get this class’ instance from a base class depending on your design (or your reconsideration). Maybe you can get this class’ instance from a class that would not be that awkward to have as an global instance, such as Game or World that holds the whole game state. The possibilities seem unlimited…

Another common complaint about singletons is having many variants of the singleton idea and multiple ways of implementing it. This is actually true. If it is your first time with singleton pattern and you search for an example code, you can easily face with many different implementations of the same pattern. And if you are not lucky enough to find a good source, you can easily end up with a bad implementation.

If we focus on more technical issues than the design related ones, the first thing worth to mention is thread-safety. Simple days of single-threaded programs are coming to the end, especially for video games. Now, it is the era of multithreading. When we make something globally accessible, we create a chunk of memory that any threads can see and use this chunk without knowing any other threads. This leads you to deadlocks, race conditions, and some other thread-synchronization bugs.

Let’s reconsider the naive singleton class example we mentioned above. Well, it works well with a single thread software, but in multithreading environment, two different threads can call the Instance, evaluate the if(instance == null) case true, and then create two instances of our Singleton class! This is an obvious violation of singleton pattern.

But this is not a problem with no solution. It only requires some additionally work and knowledge. For example, we can easily turn our naive singleton implementation into a thread-safe version without using locks as below:

C++11 version of the code, which uses magic statics, above would be like this:

For more information about thread-safe singleton implementation for C#, please refer to C# in Depth – Implementing the Singleton Pattern in C#.

For more information about thread-safe singleton implementation for C++, please refer:

Well, I wish multithreading was the last problem with singleton, but there is more… Singletons increase coupling. Thus, unit testing your class can become really difficult because of singletons. You may even end up with making each unit test a separate application since the singletons would be available for the duration of the application. Additionally, unit testing frameworks may interfere with your own static variables since they heavily use static variables for automated testing discovery.

You can try to solve this issue by getting your different kinds of singletons from another source, such as a factory. This can also reduce the coupling caused by singleton pattern, but does not offer a real solution.

Now, we also know why singleton is our enemy. But, this leads us to another question:

How we can tackle our enemy?

What to do for singletons?

This is one of the questions that we still do not have a certain answer and the war between pro-singleton and anti-singleton people are going on. But, I think the number of the neutral ones (or maybe the logical ones?) are increasing day by day, too.

I think we can say that there are four alternatives to tackle singletons. The very first option comes to mind is global variables. I will say right away (as I said before), this is the worst solution unless you really have a good reason or strong design to validate it. Otherwise, it will be like throwing a barrel of gasoline to the fire. You will only increase the coupling and make the flow of logic extremely hard to follow.

The next possible solution is just let your singletons be. But, as we saw earlier, singletons will make the maintenance and unit testing harder, plus you have to be sure that they are thread safe.

The next possible solution is dependency injection (DI), anti-singleton people’s favorite. Dependency Injection is indeed a 25-dollar term for a 5-cent concept. In a very basic explanation, it is passing the service as a constructor parameter. So, instead of making your class a singleton, you will pass it to the related classes and keep a reference, pointer, etc. there.

If you apply a good OOP design, thanks to having the service inside the class, you can eliminate coupling problems. It is also thread safe since each thread would have its own instance of every service. Finally, DI is naturally ready for unit testing.

It sounds like we are in heaven, right? But what about the memory usage? DI will take up more memory since every instance of a class needs a reference to every service it will use. Imagine, you are on a 64-bit system, writing a game with C# (.NET), you need 10 services to keep references in a class, and you will have 10 000 instances of this class. Well, then you will use 0.8 MB only for the references of these services! Plus, what about having too many services and no frameworks to handle it for us and being forced to handle everything on our own, as C++’s case? Too much work…

The final solution we are offered is service locator pattern. Service locator is basically a class holding the instance of every service you have. So, when you need to add or use a service, you will always refer to your service locator class.

But, this brings us back to where we started… How will we access to the service locator? As a global variable? As a singleton? Via dependency injection? But, at least we will ask this question and apply the solution only for a single class instead of dozens of service (e.g., if you consider the DI example above, you can reduce the cost of references from 0.8 MB to 0.08 MB by using an injected service locator).

Service locator also allows unit testing (you can always mock calls) and lowers the coupling.

Conclusion

When I started to write this article it was January 2019. When I publish it, it will be probably February 2019. At the moment, I still believe that I could not find a real alternative to singleton.

Dependency injection seems like a hero coming to save us from the evil singleton, but when his heroic magic loses its effect, you can see that DI also has some important flaws.

Service locator seems as the answer we seek, but it turns out something like a paradox since it leads us back to question how to represent it (a global variable? A singleton? Dependency injection? Putting into a service locator?!).

But at the moment, my personal preference is immigrating to a service locator that will be represented as a thread-safe singleton. Because, I still think that for game development, injecting all the services are not very realistic and service locator does not create any hardships for unit tests.

References