What’s so bad about the Singleton?

Share this article

I keep running into people who caution against using Singleton and recommend to avoid it like a plague. What is so scary about it?
Kailash Badu

It’s a good question, for it is true that global variables are often demonised and more recently the Singleton has befallen the same fate. Perhaps a bit surprising, it is remarkably hard to find good arguments to support this common knowledge — Googling turns up a lot of confusion.

As I have often taken this stance myself, I found it reasonable that I should be able to argue for it, so I’ll try to give an explanation. This is also in part a follow-up on my post from last week, in which I present a way to avoid global symbols, without spending much time on why.

The anatomy of the Singleton

Some of the confusion around Singletons, comes from the fact that it is a manifestation of two different concepts, which each have a negative effect on an applications architecture. This muddies the case, since people tend to only deal with either one or the other of these two.

The most obvious of these concepts, is that the Singleton is a form of global state. It has this in common with global variables, as well as a couple of other — less obvious — manifestations hereof.

The other concept, that the Singleton contains, is that of static binding. Both of these are closely related to scope, which again has to do with drawing clear boundaries between sub-parts of a program.

But I’m getting ahead of myself.

Program state

Perhaps the simplest way to understand a program, is in terms of data and code. These two exists in separate worlds, with different rules associated. As the code executes, it manipulates the data, producing some kind of result. The data in a program, is known as state.

Since the basic unit of a program, is a function, state usually refers to the data, which relates to a function. A function is said to be stateful, if it changes it’s context, when run or if the context has any effect on the outcome of the function. Some times the term side-effects is used to describe the same thing. A function is said to be pure, if it always produces the same output, given the same input. For example, the following is a pure function:


function add($a, $b) {
  return $a + $b;
}

In the same terminology, a function which isn’t pure, is called a procedure. This is where the term procedural programming comes from. The following is an example of a procedure:


function add($a, $b) {
  echo ($a + $b);
}

Different shades of state

Global variables are a specific type of program state, but it’s not the only one. The above example (2) has a side-effect, without using a global variable — It writes out to the standard output. Another common kind of state, is mutable objects. For example, an object, which has a setName() -method, that changes the objects name, has side-effects (But the side-effects have a smaller scope, than global variables do). Even a local variable is stateful, within that functions body. While these are all examples of state, they represent different degrees on the scale.

What’s the problem, again?

As you may have guessed from the terminology (pure => good, side-effects => bad), it is implied, that state is bad.

The consequences of side-effects are two-fold. On one hand, they cause complexity. The problem is, that the i/o isn’t explicit. There is no way to know, by looking at the interface alone, what happens when invoking a function. This may be a small scale problem, but it adds up as the program grows.

The other problem is that of coupling. Since state can be shared between different functions, it may introduce a dependency between these functions. For example, if classes A and B both access the global variable G, then it is impossible to change G for A, without also changing it for B. This kind of dependency is called coupling.

There are remedies for excessive state in programs: Global variables can be replaced with local ones. Local variables can be replaced with function-calls (replace temp with query). Objects, which are passed around could be made immutable– This is especially important for long-lived objects, which interact with many parties.

Static binding

A program has two different kinds of existence; The compile-time and the run-time. Interpreted languages alternate between these, while a compiled language has a stricter separation. In any case, the symbols of a program, which take on a meaning in the compile-time, can’t change it’s meaning in the run-time. Examples of such symbols are constants, literals, class names and static methods (And in PHP, floating functions). Runtime-symbols (variables), on the other hand, can change their meaning.

Even though static symbols can’t change, they can still influence the outcome of a function, so in a very general sense, they are a form of state. It is usually not as important to avoid the state of static symbols, but in some cases, they may cause the same problems, as run-time state does. For example, static method calls cause static (compile-time) coupling. The Singleton is a prime example of this kind of coupling; If class A uses singleton S, then there is a strong coupling between A and S.

coupling

Coupling is of course unavoidable and to some extend even desirable. However, just like with run-time state, limiting it is a good idea. The problem with static coupling, is that it makes it hard (or even impossible) to reuse a component in isolation from other components, which it is coupled to. This is usually not an immediate problem, but it can have impact on maintenance. It also makes it hard to unit-test and debug code, because it isn’t possible to isolate a part of your program.

That’s all

I only just scratched the surface of the topic, but I hope this offers some explanation of why globals are frowned such upon. I’ll just leave you with the following quote:

Forgive Me Father, for I Have Singleton’ed
Kevlin Henney

Comments are — as always — welcome, but please refrain from biting off heads (Mine or others).

Troels Knak-NielsenTroels Knak-Nielsen
View Author

Troels has been crafting web applications, as a freelancer and while employed by companies of various sizes, since around the time of the IT-bubble burst. Nowadays, he's working on backend systems for a Danish ISP. In his spare time, he develops and maintains Konstrukt, a web application framework for PHP, and is the organizer of a monthly PHP-meetup in Copenhagen.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week