Global states and evil, evil singletons

Some questions about what to allow in a global state:

I’ve always liked my singletons, but suspected I was using then too liberally (especially when doing plugins - where shared memory is a definite no-no).

So … After some discussion with the sagely mattsonic (from this forum), and reading some hate mail on singletons, I was convinced to try removing all my singletons and cause my dependencies to become explicit (mostly by including them in constructors and then centralizing all the constructors in a builder class). This makes tremendous sense to me, because dependencies should be clear after all. If an objects initializes and then later conjures a singleton from midair to provide a needed link … well, that’s not exactly modular is it?

So far, so good … six sessions of heavy coding and I am nearly rid of my global objects.

However …

There are surely some things that can still be in a global state? For example, I see in the Juce docs that for the AudioDeviceManager …


“The idea is that your application will create one global instance of this object, and let it take care of creating and deleting specific types of audio devices internally. So when the device is changed, your callbacks will just keep running without having to worry about this.”

… awesome, done. I place this in a singleton state object and it can then be accessed from various places around the code. And this is safe, clearly.

some other examples are not so clear cut to me … like …

Colours … I have a long list of Colours that are referenced by various UI elements. Colours are atomic, yeah? And since their are some stored already in the LookAndFeel singleton … this must be safe.

or a Changebroadcaster? Or value object?
I have some of these to trigger things like “midi learn mode” … which many, many objects need to be able to see … so where better than on a singleton?

How about a propertiesSet? ApplicationCommandManager? knownPluginList?

I am probably missing the key guiding principle here, and certainly I am continuing to change my mind about singletons every time I read a few more articles … but any discussion here would be great. I want to make sure to strike the right balance.

You’re right to avoid singletons. But don’t misunderstand my comments on the AudioDeviceManager - saying ‘global’ there is probably a bit misleading. Sure, you should probably have one instance of it, but there’s no reason why that should be a in singleton rather than just owned by your application object or some other object. In my own code I don’t think I ever use AudioDeviceManager as a singleton.

For global constants, colours, etc. you may want to just make them static, which is generally ok as long as they’re read-only.

To try to summarise the reason why singletons/statics are bad: Ideally, when you write a class, the class should only operate on its own internal state, and on any data that you explicitly give to it. That way, there’s no danger that it’ll have unexpected side-effects when you use it. By allowing singletons, ANY part of your code, and ANY class may actually be messing with global state behind the scenes, so could have unexpected interactions with other, completely unrelated bits of the code. That’s bad design.

So wherever possible, if a class needs to access some kind of shared object, you should explicitly give it a pointer/reference to that object, so that at least it’s obvious by looking at the class which other objects it uses.

(I know this conversation is from nearly a decade ago, apologies for the necromancy.)

And also makes proper unit testing nearly impossible, because any tests you perform on the singleton object can suddenly affect the outcome of other, unrelated tests. (Only after encountering this problem did I finally understand the bias in CTest — CMake’s test platform — towards executing individual tests as separate processes, each performed in total isolation from all of the others. It initially seems wasteful/insane for there to be hundreds, even thousands of separate processes launched in the course of running a set of tests, but turns out it’s For Reasons™.)

“Centralizing” certain things in singletons always seems like a good idea at first, since it means there’s only one place to look for certain data, only one place it needs to be updated to take effect everywhere, only one place where things have to be synchronized to keep the code thread-safe. But eventually you nearly always find some instance where it would be advantageous for some part of the code to maintain its own state separate from the singleton object.

There are a very, very few reasonable uses for singletons. Our logging class is one, and so far I’m not seeing any reasons why I’d want to complicate things by changing that. It does still make it nearly impossible to unit-test, but then unit-testing logging is difficult anyway.

The settings interface that configures whether logging is enabled and how, though, is also a (different) singleton. That’s already becoming a problem, because it means we’re stuck with only the coarsest possible configurability for logging across the entire codebase.

Since we’re digging up sh*t here, isn’t it true that the JUCEApplication class is a singleton?

It’s similar to a singleton in that there should only ever be one JUCEApplication object, and there’s a getInstance() method that you use to return that single instance. But the class itself is not a singleton since the constructor is public. As long as you create a subclass that overrides the pure virtual functions, you can create as many instances as you like.

Not sure what you mean by “digging up sh*t”, but this is a good example of a class that isn’t using the singleton pattern, despite its use case having singleton-like characteristics!

Thanks for the explanation.

(I was referring to your necromancy comment, and the fact that I thought my question would be controversial. But it turns out that I was wrong).

1 Like

Hey, “digging sh*t up” — guilty as charged. “Stirring sh*t up”… well, maybe that too, sometimes. :wink: