• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
neotms

Singleton pattern abuse

45 posts in this topic

Alright so I started coding as a hobby a few years ago and im [b]slowly[/b] 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? [img]http://public.gamedev.net//public/style_emoticons/default/tongue.png[/img]). 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 [img]http://public.gamedev.net//public/style_emoticons/default/tongue.png[/img]) 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.
0

Share this post


Link to post
Share on other sites
[url="https://www.google.com/search?q=site%3Agamedev.net+singleton#q=site:gamedev.net+singleton+bad&hl=en&tbo=1&prmd=imvns"]There are lots of post on this subject.[/url]


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.
1

Share this post


Link to post
Share on other sites
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?
0

Share this post


Link to post
Share on other sites
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! [img]http://public.gamedev.net//public/style_emoticons/default/laugh.png[/img]
[quote name='neotms' timestamp='1339170656' post='4947402']
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.
[/quote]
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 [i]much[/i] 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.
1

Share this post


Link to post
Share on other sites
[u][i][b]Any[/b][/i][/u] use of a singleton is abuse.


[quote name='neotms' timestamp='1339170656' post='4947402']
Is the singleton pattern such a curse that if I find I have to use it there is something wrong with my class structure?
[/quote]
Yes. There are no exceptions to this rule.


[quote name='neotms' timestamp='1339170656' post='4947402']
The problem is that in a multiple file project some data will need to be available in more than one place.
[/quote]
No, the problem is that you think a singleton is the answer to this “problem”.
Design better.


[quote name='neotms' timestamp='1339170656' post='4947402']
Here is an example for those interested. …
[/quote]
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
-1

Share this post


Link to post
Share on other sites
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. :)
1

Share this post


Link to post
Share on other sites
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.
-2

Share this post


Link to post
Share on other sites
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).
2

Share this post


Link to post
Share on other sites
I'd like to thank everyone for their time, I've realised from answers in the post that the way to get rid of singletons is review my design and get rid of the dependencies even if I don't like the idea of it. I'll start working on separating rendering functions from my objects when I get the time. :P

[quote name='Narf the Mouse' timestamp='1339211749' post='4947556']
Bobs' personal data doesn't need to know how it's drawn.
[/quote]

But a map (talking about 2D) which is rendered tile by tile is rendered differently from, say, a checkbox or any simple object that only needs to be rendered with one procedure. Mustn't the Map class know of the logic by which it'll be rendered? (nested loops etc). Otherwise, that information must be hardcoded somewhere else (renderer?).
0

Share this post


Link to post
Share on other sites
[quote name='neotms' timestamp='1339238708' post='4947625']
I'd like to thank everyone for their time, I've realised from answers in the post that the way to get rid of singletons is review my design and get rid of the dependencies even if I don't like the idea of it. I'll start working on separating rendering functions from my objects when I get the time. [img]http://public.gamedev.net//public/style_emoticons/default/tongue.png[/img]

[quote name='Narf the Mouse' timestamp='1339211749' post='4947556']
Bobs' personal data doesn't need to know how it's drawn.
[/quote]

But a map (talking about 2D) which is rendered tile by tile is rendered differently from, say, a checkbox or any simple object that only needs to be rendered with one procedure. Mustn't the Map class know of the logic by which it'll be rendered? (nested loops etc). Otherwise, that information must be hardcoded somewhere else (renderer?).
[/quote]
All the map class need know is it has an array[][] of tile data; all the renderer need know is it's received an array[][] of tile data.

And the renderer doesn't need to be hard-coded to draw specific tiles; a factory can fill out a lookup table of some sort.

Classes shouldn't have more than one concern, even if that concern is "Running the game". Even the class that "Runs the game" shouldn't concern itself with, say, whether or not BobMob gets drawn.

Of course, as always, real life is not ideal and sometimes what works still works well enough.
2

Share this post


Link to post
Share on other sites
If the idea that globals are bad because you need to keep track of so many potential modifications in different functions then I can hardly see how passing a reference to them solves this problem since you can still modify the original value from different places. At some point you'll have states that the entire program needs to keep track of so this jihad seems a bit too dogmatic. Not all programmers have a phd in computer science so these considerations seem to paralyse by over-analysis rather than just let you code away. I'm victim of this.
1

Share this post


Link to post
Share on other sites
[quote name='Fredericvo' timestamp='1339341670' post='4947930']
If the idea that globals are bad because you need to keep track of so many potential modifications in different functions then I can hardly see how passing a reference to them solves this problem since you can still modify the original value from different places. At some point you'll have states that the entire program needs to keep track of so this jihad seems a bit too dogmatic. Not all programmers have a phd in computer science so these considerations seem to paralyse by over-analysis rather than just let you code away. I'm victim of this.
[/quote]
If I understand your argument, it's that passing, say, TextureManager everywhere is just as bad as a Singleton, so why not use a Singleton?

1) That sounds like an argument against passing TextureManager everywhere.
2) The thing is, if you want to change what a pass-by-value system uses, you only need to change a few upstream values. If you want to change what a Singleton system uses, you have to re-write it to a pass-by-value system.
0

Share this post


Link to post
Share on other sites
No I'm not saying it's better or worse, just that the alternative isn't that obvious to me. Let's say in scenario A you have a global, gState = 1;
then you have somefunc1(); reading/modifying it.
And func2() and func53() and func89 () and you forgot that func15() also modified it. They say "see! Globals are evil"
Now in scenario B you made it local and passed a reference to all of the above functions and maybe you also forgot that func15() changed it.
Then did you really solve the problem?
But you polluted the namespace less I guess?
0

Share this post


Link to post
Share on other sites
I don't think anyone in this thread has a PHD in computer science (though I may be wrong). On the other hand, I'm 100% confident that the more vehement posters have lost months of their lives to singletons that seemed 'convenient' to someone at some point.

+1 phantom's mention of const - another invaluable tool in making it possible to reason about your code. Edited by mrbastard
0

Share this post


Link to post
Share on other sites
[quote name='Narf the Mouse' timestamp='1339342895' post='4947936']
2) The thing is, if you want to change what a pass-by-value system uses, you only need to change a few upstream values. If you want to change what a Singleton system uses, you have to re-write it to a pass-by-value system.
[/quote]

Just a thought... whether you're using a pass-by-argument sort of thing, or a singleton, you're still using that object in the same places. In the example given, the TextureManager is being used in function used for loading stuff. Whether the Mgr is available as a global/singleton or it's passed as an argument (or some other object containing some context data that could be used in lieu of the Mgr), if you make a change to it, you need to account for the change in that function. It really doesn't matter. Putting it in a singleton just makes it easier to call the loading function. If anything, the singleton requires an equal or lesser number of changes, since you don't have to change upstream references, just the actual usage.

There's been mention of not being able to see at a glance what data/objects a function uses, and forgetting about updating references when changes are made... true, you don't get the same immediate indicator that a load function is going to use some sort of content system as you would if you passed it as an argument. Instead you've got, well, the fact that it's a loading function, plus perhaps some documentation for the function that says something like "gets the appropriate texture from the TextureManager". As far as forgetting to update references, I'm sure the IDE can help you with that; just do a search for the class name, it's a singleton, so you probably don't have to worry about it being referenced using some subclass (there may be a subclass, but you're likely using the base class' name).

[quote name='Narf the Mouse' timestamp='1339222796' post='4947579']
2) If you have an easily-accessible hammer...
[/quote]
... then when you need a hammer, it's easy. If that hammer is complicated, you're going to start using the butt of a screwdriver or a shoe to pound nails.


Personally, I won't shy away from singletons (or really, anything) when I feel they are appropriate. An example for me, something I've used in pretty much any project: I generally have some sort of Event Dispatcher, which allows listeners to register for certain event types, and then anyone can fire out events as appropriate. Fairly similar in concept to Win32's message stuff. Pretty useful, I'm sure there are other solutions, but this is the one I like to use, and it has evolved over several projects. It means, for example, that an explosion class doesn't need to get a list of all nearby actors and manually call a dealDamage() function or anything. Instead, damageable actors register for the EXPLOSION event, and the explosion fires the event (either the actors check if they're in range, or I could implement some sort of filter to decide which listeners will actually get the event). Sure, a lot of things end up being connected to the EventDispatcher singleton, but that's never been a problem for me. You might say "oh, but that can't be thread safe!" Well, it's no different than getting nearby actors and calling dealDamage() on each of them. And there's no way I want to pass an EventDispatcher around to every single object I create (not every object uses it, but we don't want to lock that sort of assumption into the code now, do we)


My general opinion is that you shouldn't dismiss something just because everyone says it's bad. I feel pretty confident in saying that [i]any[/i] construct has some case where it is appropriate. Sure, there are places where a singleton is far from the right tool, but sometimes it's going to be much cleaner than the alternative. I see several people here saying that singletons are pure evil and should never be used under any circumstance. I say use whatever makes sense. If using a global object or a singleton is going to make your code cleaner and simpler than passing extra context objects around, use it! If down the road you find that you're running into problems with it, then you can change it up. [b]Especially[/b] since the OP stated outright s/he's doing this as a hobby, and wants to learn. What could be better for learning what works and what doesn't, than trying it out? If you try something and it works through to project completion, great! If you find that at some point it's no longer sufficient, then you'll understand [i]why[/i] it doesn't work and can move to a better solution. Sure, it may take a bit of time to refactor, but the experience is, I think, a lot more valuable that someone just telling you "it's bad, never do it."

Of course, I'm not saying that everything can/should be a singleton either, just do what makes sense to you.

And back to the OP's example of the TextureManager... my opinion would be that you could instead have a single ContentManager, which defers requests to the TextureManager, ModelManager, SoundFileManager, WhateverElseManager as appropriate based on resource type; so it's one singleton instead of many. Or instead of separate *Managers, provide separate *Loaders for each resource type, and ContentManager maintains a list (or whatever your favorite container is) of generic Resources (which is subclassed or something for each resource type) provided by those *Loaders.
1

Share this post


Link to post
Share on other sites
[quote]
Just a thought... whether you're using a pass-by-argument sort of thing, or a singleton, you're still using that object in the same places.
[/quote]
In my experience, once an object becomes globally accessible, the probability of "unnecessary" accesses increases enormously. So, no, I think in practise one finds that your average global will be accessed by considerably more areas of the code than the same state would be accessed in a less coupled design.

Also, once there is at least one globally accessible object, the probability of other (arguably far less worthy - it is easy to argue for a global texture cache) candidates being "promoted" to globally accessible increases too.
1

Share this post


Link to post
Share on other sites
[quote name='rip-off' timestamp='1339352601' post='4947984']
[quote]
Just a thought... whether you're using a pass-by-argument sort of thing, or a singleton, you're still using that object in the same places.
[/quote]
In my experience, once an object becomes globally accessible, the probability of "unnecessary" accesses increases enormously. So, no, I think in practise one finds that your average global will be accessed by considerably more areas of the code than the same state would be accessed in a less coupled design.

Also, once there is at least one globally accessible object, the probability of other (arguably far less worthy - it is easy to argue for a global texture cache) candidates being "promoted" to globally accessible increases too.
[/quote]

True enough, it is important to practice some self control to avoid overusing them. But just because there's a risk of over-/misuse is no reason to completely discard something.

I refer you to [url="http://www.codeproject.com/Feature/HallOfShame.aspx?msg=3547702"]this lovely piece I wrote some time ago[/url]. I'm actually quite proud of it (especially the second version, near the bottom of the page). In it, just about everything I've used has been misused. But it's no reason to condemn any of them (can't say for loops are bad just because it's possible to put the entire loop body inside the conditional and/or increment sections); only those particular cases. But, that's getting a bit off-topic I think.
0

Share this post


Link to post
Share on other sites
[quote name='Sir Timothy' timestamp='1339354691' post='4947993']<br />I refer you to this lovely piece I wrote some time ago.<br />[/quote]

I don't understand your point here. That code is over-complicated, difficult to understand and hard to maintain and can be implemented far more simply at no significant cost. Many of the arguments against singletons would apply equally to that code.

There are many reasons to condemn the majority of your code I'm afraid. "It works" is about the only thing that can be claimed in its favour, which is subject to testing to confirm.
0

Share this post


Link to post
Share on other sites
[quote name='Sir Timothy' timestamp='1339354691' post='4947993']
I refer you to [url="http://www.codeproject.com/Feature/HallOfShame.aspx?msg=3547702"]this lovely piece I wrote some time ago[/url]. I'm actually quite proud of it (especially the second version, near the bottom of the page). In it, just about everything I've used has been misused.
[/quote]

That's a nice one! I like the way you use the commutative property of the indexing operator..

I once created an encryption program. It used C as input, and produced compilable C as output. If you change all identifiers and expand most local header files, the source code can become really hard to understand.
0

Share this post


Link to post
Share on other sites
[quote name='Aardvajk' timestamp='1339418350' post='4948139']
[quote name='Sir Timothy' timestamp='1339354691' post='4947993']<br />I refer you to this lovely piece I wrote some time ago.<br />[/quote]

I don't understand your point here. That code is over-complicated, difficult to understand and hard to maintain and can be implemented far more simply at no significant cost. Many of the arguments against singletons would apply equally to that code.

There are many reasons to condemn the majority of your code I'm afraid. "It works" is about the only thing that can be claimed in its favour, which is subject to testing to confirm.
[/quote]
I think the key comes from the next sentence: "In it, just about everything I've used has been misused." I think the code is more satyrical in nature, showing you all the wrong ways to use otherwise useful aspects of C. Which would make sense in the context of his earlier post, where he's neither really for nor against singletons, but mentions it's easy to abuse them (i.e. I think his point his: do you condemn the pattern or do you condemn the use of the pattern?).

I won't repeat my personal opinions ([url="http://www.gamedev.net/topic/621895-alternative-to-singleton/"]which I expressed here[/url]), as this topic was beat to death on these forums within the last 3 months. I will say, however, that I have never seen the singleton used properly. Ever. It's always used as a "OOP global variable" (I mean, really people?), or as an absolutely unnecessary restraint on some aspect of the program that's also inappropriately given static duration. People just need to stop using it so they stop using it wrong.
2

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0