Singletons

Started by
39 comments, last by Way Walker 15 years, 3 months ago
Quote:Original post by kyoryu
Problem is that singletons are often used to enable global access, rather than control instantiation. They're often basically used as an "OO-compliant" version of globals (which isn't really the purpose).

Instead, they should be used when only ONE instance of the class should ever be instantiated... as in "bad things will happen if there are two of these around." If the singleton still implements an interface, you can still pass it to objects via dependency injection.

So they're not inherently bad, just almost always misused. Sniff test: A singleton that doesn't implement an interface is most likely a misuse of the pattern.


Word.

It's funny to watch these threads pop up regularly..

I think Singletons are a hapless victim of people's love affair with OOP. I guess we all have to hate something.
Feel free to 'rate me down', especially when I prove you wrong, because it will make you feel better for a second....
Advertisement
Quote:Original post by scratt
Quote:Original post by kyoryu
Problem is that singletons are often used to enable global access, rather than control instantiation. They're often basically used as an "OO-compliant" version of globals (which isn't really the purpose).

Instead, they should be used when only ONE instance of the class should ever be instantiated... as in "bad things will happen if there are two of these around." If the singleton still implements an interface, you can still pass it to objects via dependency injection.

So they're not inherently bad, just almost always misused. Sniff test: A singleton that doesn't implement an interface is most likely a misuse of the pattern.


Word.

It's funny to watch these threads pop up regularly..

I think Singletons are a hapless victim of people's love affair with OOP. I guess we all have to hate something.


Did you even read the real and tangible reasons for avoiding them?
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
Quote:Original post by M2tM
Quote:Original post by scratt
Quote:Original post by kyoryu
Problem is that singletons are often used to enable global access, rather than control instantiation. They're often basically used as an "OO-compliant" version of globals (which isn't really the purpose).

Instead, they should be used when only ONE instance of the class should ever be instantiated... as in "bad things will happen if there are two of these around." If the singleton still implements an interface, you can still pass it to objects via dependency injection.

So they're not inherently bad, just almost always misused. Sniff test: A singleton that doesn't implement an interface is most likely a misuse of the pattern.


Word.

It's funny to watch these threads pop up regularly..

I think Singletons are a hapless victim of people's love affair with OOP. I guess we all have to hate something.


Did you even read the real and tangible reasons for avoiding them?


Yes. I also use them daily, and am aware of all the pitfalls. But I still attest they have their uses, and their are often times they are a good solution to a problem.

Elitism is not something I aspire to.

Feel free to 'rate me down', especially when I prove you wrong, because it will make you feel better for a second....
Nobody said anything about elitism. What are you talking about? Discussing technical merits and pitfalls and suggesting it is a good idea to avoid global data when possible does not equal elitism at all.

It's pretty a basic object oriented principle that you should avoid doing things that subvert encapsulation and introduces ambiguous dependencies. Because the Singleton pattern deals with objects and is easily misused it is not unreasonable to stress the importance of very, very careful consideration before implementation. Typically they are more indicative of design failure than a genuine need to actually use them.

Give some examples of where you think the Singleton design pattern is a good idea if you're set on proving a point. Otherwise you are spouting conjecture without any real specific reasons to back up an argument for Singletons. I myself have provided an example of a good candidate for Singleton use, but there aren't many. If you can paint a picture of exactly what situations you think call for a global single instance with real examples I'll take you more seriously.

The unsubtle and completely unrelated jabs at the community combined with the vague condescending tone don't do it for me.

[Edited by - M2tM on January 22, 2009 5:08:48 AM]
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
Quote:Yes. I also use them daily, and am aware of all the pitfalls. But I still attest they have their uses, and their are often times they are a good solution to a problem.

Elitism is not something I aspire to.
The issues people tend to bring up with respect to singletons are pretty cut and dried, so I don't think it's really an issue of elitism. It may very well be that your own use of singletons is fully justified. However, on these forums at least, when someone says that 'singletons have their uses', it seems that 9 times out of 10 it turns out they're talking about a texture cache or some other object that doesn't meet either of the design criteria associated with the singleton pattern. Because of this, I think we tend to be a little skeptical when someone says that they find the singleton to be a useful pattern (especially when no supporting examples are given).

As for elitism, let me just say right now that there's a lot to be said for 'getting the job done' and using whatever techniques, patterns, or tools you feel most comfortable with. However, keep in mind that a lot of these 'singleton' threads are targeted towards (and read by) folks who are early in the development process and have yet to commit to a particular approach. In this case, I think it's perfectly justified (and not elitist) to put forth the arguments for and against singletons in no uncertain terms, so that beginning developers are better equipped to make good design decisions early on.
Quote:But I still attest they have their uses, and their are often times they are a good solution to a problem.


Such as?
Quote:
let me just say right now that there's a lot to be said for 'getting the job done' and using whatever techniques, patterns, or tools you feel most comfortable with.

I agree with this.

In my experience trying to 'get the job done' the following is faster than throwing together the necessary Singleton boilerplate code.
class Example{   // ...};Example &global_example(){   static Example example;   return example;}

So even if you choose (or don't have a choice!) to do a quick and dirty job you don't have to use Singletons. Later on I refactor if necessary.
Hmm that Google vid is pretty good.

So Static Classes are basically Singletons eh? I'll admit I use them a fair bit for classes that (a) have no real state, (b) have no external dependencies, and (c) and many other un-related classes need to call.

For example I have static SoundManager class. A ton of classes need to play sounds including: Input, UI, Buttons, Gun, Explosion, Impact, all AI classes, Player, Collision, etc. Putting a "refToSoundManager" in every one of those classes seems inferior to be able to just call SoundManger.PlaySound().

Random Number Generator is another example. A ton of classes need to generate randoms and it doesn't seem logical that a Monster class should have a "refToRandomNumberGenerator" as a class variable.

Used in this manner Static Classes seem like the equivalent of #including a file, using a DLL, or running a service.

[Edited by - EJH on January 22, 2009 3:04:47 PM]
Quote:Original post by EJH

For example I have static SoundManager class. A ton of classes need to play sounds including: Input, UI, Buttons, Gun, Explosion, Impact, all AI classes, Player, Collision, etc. Putting a "refToSoundManager" in every one of those classes seems inferior to be able to just call SoundManger.PlaySound().


Sure. Until you need the option to control sound generation on per context-basis.
- Input and UI need simple, constant (UI setting) volume sounds
- Gun, Explosion and Impact all need to generate spatial sound. Environment generates those from their own resources
- Player generates several types of sounds. Some are spatial, others are same as UI (out of ammo warning is not spatial sound)
- Music is on different volume, so are some ambient sounds, some AI chatter, some events
- Depending on settings/hardware, you may need to limit number of sounds currently played. But this requires you to know which are important and which can be omitted. For example, rat squeek is omitted, but not if player stepped on it.
- Next, you want player to be able to play their own mp3s instead of music. To correct for volume, you hash each individual mp3 and remember player's volume setting.
- And so on....

So you end up with a huge mess of dependencies between all different subsystems which need to know about every aspect of the design.

Quote:Random Number Generator is another example. A ton of classes need to generate randoms and it doesn't seem logical that a Monster class should have a "refToRandomNumberGenerator" as a class variable.


Which works, until you go into networking, and want to share the RNG across all clients, so they advance deterministically.

Even more, RNG is needed in multiple threads. It is also used by some non-shared systems, which behave differently depending on which platform you're running on.

For example, the AI and Logic RNG needs to be completely deterministic, even though they each run in separate threads. But particle system RNG is used by arbitrary number of threads, depending on how powerful a certain machine is (1 core, 1 particle thread, 4 cores, 3 particle threads, 3 times as many particles and calls to RNG). Logic and AI use Mersenne for better results, particle system uses default, fast version. or Mersenne as well, if default RNG produces too visually skewed results. Or you choose on the fly, depending on client performance.


Problem with globals in general is that they don't scale with regard to project complexity and actually make the problem worse.

Global context can be convenient in some cases, simply due to reduced typing and implicit dependencies. But even then, it commonly saves a few characters of typing, and on some rare occasions sizeof(void*) of memory.

But those cases are so limited, or so specialized, they need to be considered individually.

The main point is - if you start with globals and singletons, changing that is really hard, or in actual projects, closer to impossible. Nobody is going to allow you to change singleton to instance 1 week before project ships, since it requires restructuring of entire code.

Contrary to regular class, which can be, at any given point be turned into a singleton using a templated wrapper, should the need for a single instance arise.
Quote:Original post by kyoryu
People use it like that, IMHO, because globals are really convenient, and wrapping it in a design pattern (even if it's being misused) somehow blesses the global.


I would also add that the extra work done in building the framework feels good. It feels like you're doing something useful even if you're not, and the extra work is fairly mechanical even if you're unlikely to get every corner case correct. This is part of why I think C++ is so popular, and it took me working in Smalltalk to realize it. The only thing I'd add to rip-off's code is the line "// Do not create more than one instance of Example". Quick and dirty. If you have time to do something better, you have time to do something better than a singleton.


For the SDL_mixer example, what's the problem with free functions? Why not just place all of the function and variables in a namespace? Or, if you want to have private data, why not a class with only static members? (Which was actually the first suggestion in the linked thread.)


Actually, I've always wondered why there's no love for singleton's sister, the monostate. It's easier to implement (no added trickery to prevent multiple instances, just type "static" before member variables), does basically the same thing (replace calls to "getInstance()" with calls to the constructor), but you can think of each instance as a handle to the class. I've never done anything with multiple threads, but it seems it could cleanly handle mutexes with RAII.

This topic is closed to new replies.

Advertisement