Singleton pattern abuse

Started by
44 comments, last by freakchild 11 years, 10 months ago
Alright so I started coding as a hobby a few years ago and im slowly learning new things and finding out what is good practice and what not, but recently after reading some articles about the singleton I've become confused. I'd like to discuss and get advice on the singleton pattern use. I know it's a very discussed subject on the internet and my questions may already be answered on some other post but I haven't managed to find a good place answering my questions.

I have a project I'm working on which is constantly growing and becoming more structured and complicated. At some point I read using globals is bad (try reading that in professor Mackey's voice from South Park, mkay? tongue.png). And at that point I was using many globals. So I searched for an alternative and some people were suggesting the singleton pattern. I was excited with the idea and replaced my globals with singleton classes (as necessary, some globals were probably removed tongue.png) and by the time I was done I had a few singleton classes.

Now I'm reading around some articles saying the singleton pattern is bad. I understand their arguments and realised that some of my singleton classes were an overkill so I changed them and I'm still in the process of rechecking my files and seeing if I can remove more singletons (because I honestly have too many atm). But I just can't get rid of some of them.

Is the singleton pattern such a curse that if I find I have to use it there is something wrong with my class structure? The problem is that in a multiple file project some data will need to be available in more than one place. So how should I achieve this state of "global" access? (Not entirely global, but more than local anyway)

Here is an example for those interested. My TextureManager class is a singleton. It's mostly used in an object loading function to find a texture if loaded in memory or load it otherwise. How can I access my texture manager in the object's load function if it's not a singleton? Pass it as an argument? Keep a pointer to it as a member of the class? None seem very efficient to me. Even if passing it as a reference isn't slowing performance, it makes functions more complicated than they need to be, since the texture manager reference would have to be passed down many functions to reach the load function.
Advertisement
There are lots of post on this subject.


I do not mean to pick on you, but I wonder if some people don't know a few things about google.

When you go to google, you can specify a site to constrain your results to. To search just GameDev.net, just add site:gamedev.net to your query string.

So, you can search for singleton information on Gamedev using the string "site:gamedev.net singleton bad". You can then narrow down the search results by date range if the results are not relevant.



To actually answer your question, there are a few problems with Singletons.

First, they don't scale for #$@#$, so if you end up multithreading your code, your singleton is going to quickly become a locking bottleneck, or worse, you don't lock, in which case you are going to have some nasty bugs.

Second, they are generally abused, in the end, a singleton is mostly just a global in a pretty dress. They suck for most of the reasons a global sucks.

There are times to use globals, and thus there are times to use a singleton; but they aren't nearly as common as people think they are.
I've used the search function (though I have to admit I didn't use google that way, thanks for the tip :P) and I've mostly found posts explaining why they are bad and have to be avoided. I'm more interested in hearing alternatives that replace what a singleton provides, specifically about how singletons can be used to refer to the same data globally.

Perhaps I didn't stress that enough, I'm sorry.

I understand the sollutions may be specific to the code so a generic answer can't be provided, but how else could something like that be achieved? I've provided an example of a singleton class I can't see how I could replace. Do you (or others, for that matter) think this is a case where a singleton is necessary or am I not thinking outside the box?

I've used the search function (though I have to admit I didn't use google that way, thanks for the tip :P) and I've mostly found posts explaining why they are bad and have to be avoided. I'm more interested in hearing alternatives that replace what a singleton provides, specifically about how singletons can be used to refer to the same data globally.

The general answer is: You don't need to refer to something globally. Usually doing so is a case of a design gone bad, A code smell.

Perhaps I didn't stress that enough, I'm sorry.

I understand the sollutions may be specific to the code so a generic answer can't be provided, but how else could something like that be achieved? I've provided an example of a singleton class I can't see how I could replace. Do you (or others, for that matter) think this is a case where a singleton is necessary or am I not thinking outside the box?
[/quote]
Not really, most of the use cases for singletons revolve around: "I want to access X, but its not 'OO' to use a global, so I'll dress it up in a class and call it 'OO'!".

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

With respect, you haven't given an example of a singleton you can't see how you could replace - you've given an example of a singleton you can see a couple of ways to replace. You just don't like them! laugh.png

How can I access my texture manager in the object's load function if it's not a singleton? Pass it as an argument? Keep a pointer to it as a member of the class? None seem very efficient to me. Even if passing it as a reference isn't slowing performance, it makes functions more complicated than they need to be, since the texture manager reference would have to be passed down many functions to reach the load function.

Don't worry about performance here: if your resource loader ever sees any heavy duty use you're going to want to it to be thread-safe, and it'll be more work to lock your singleton instance for every possible eventuality than it is to pass around a few references.

Likewise, you may have the wrong instinct on complexity here - it's much much easier to reason about chains of functions passing references than devil-may-care global accesses everywhere. You've probably already seen some of this while removing the other singletons you talked about, but (at least in my experience) it only gets worse as your codebase gets bigger. Complexity in terms of typing/reading is just par for the course - complexity in understanding side effects is what you should really be aiming to reduce.

It's hard to give practical advice without seeing your code - maybe be more specific about where your loader func is used, where else uses the texture manager, and what you envisage should own the texture manager.
[size="1"]
Any use of a singleton is abuse.



Is the singleton pattern such a curse that if I find I have to use it there is something wrong with my class structure?

Yes. There are no exceptions to this rule.



The problem is that in a multiple file project some data will need to be available in more than one place.

No, the problem is that you think a singleton is the answer to this “problem”.
Design better.



Here is an example for those interested. …

Pass a structure down that contains what will be necessary for loading a texture, including any managers that may be involved.
You are passing a single parameter down barely a few functions deep. Talking about passing things down “many” functions is non-sense. It simply means you have never done it.
Once you start doing it you will realize how shallow most of that passing can be with, again, proper design.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Ok, so where is your texture manager going to be needed? Probably where you load content into your game and...That's it.

Moreover, your texture manager can be abstracted to a content manager. Same place.

If BobMob needs to load BobTexture - BobMob shouldn't load BobTexture. It should request BobTexture from the content manager.

Even more OO, BobMob shouldn't even know it needs BobTexture - BobMob is the model, not the view or the controller.

BobMob is also trying to do too much. BobModel, BobView, BobController. Bobs' personal data doesn't need to know how it's drawn. Bobs' drawing code doesn't need to know how Bob is controlled. And BobController doesn't need to know anything about Bobs' personal data, only the results of queries on that data.

(That's my admittadly beginners' perspective on Model-View-Controller. Someone else can probably put it a lot better)

And all of those should be churned out by a Factory class which can be replaced with another in an instant.

All of this is the ideal, as I understand it from personal experience and reading. :) Programming constraints aren't always ideal. :)
I actually am pro singleton for the following reasons:

1. It is a generally recognized useful design pattern that is easy to grasp.

2. It makes a single instance of an object easily accessible.

3. It is not the same as a global because it has global scope. A well written singleton can have very controlled access even though it can be referenced globally.

4. If a singleton wrecks havoc in your code, blame the programmer and not the tool.

5. Singletons make the game states that they represent easy to debug.

These are just five points that come to mind.

I actually am pro singleton for the following reasons:

1. It is a generally recognized useful design pattern that is easy to grasp.

2. It makes a single instance of an object easily accessible.

3. It is not the same as a global because it has global scope. A well written singleton can have very controlled access even though it can be referenced globally.

4. If a singleton wrecks havoc in your code, blame the programmer and not the tool.

5. Singletons make the game states that they represent easy to debug.

These are just five points that come to mind.


1) So is coding everything in Main( ) - Until you need to change something.

2) If you have an easily-accessible hammer...

3) And yet, it can still be accessed anywhere in your code. That's a downside, because now your code is locked to the global.

4) Yes. Blame the programmer who used them.

5) Here's a concept for you: One point of access failure. Local variables can only fail in the scope they're in. Globals and Singletons have multiple point-of-access failure, A singleton or global can fail *Anywhere it's been called*, yet if the error only appears *in the accessor*, good luck finding the glitch.

Here's a free #6: They're terrible for refactoring. Imagine a well-built machine. Everything works perfectly and smoothly. Except, *everything* connects to this black box.

Starting to see the problem?

I've used Singletons. I've hated it every single time and always found a better way, at some point. So, the reason to use Singletons?

1) You don't know how to not use Singletons in that context, yet, and the code needs to work.
a singleton is a global with the additional restriction that there can never be more than one instance, you should only use them when you need a global instance and there would be an error if two were created. (This is insanely rare in application/game code).

Globals aren't automatically bad, globally mutable state however is usually a bad idea and wrapping your globals in a singleton class does nothing to change this, it only makes your code less flexible. (a singleton is still a global).

If you need global access to an instance you should make it an immutable global, not a singleton. If you need globally mutable state then you should rethink your design. (Allthough it is often far more important to get the job done than it is to get the design perfect).
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

This topic is closed to new replies.

Advertisement