Singletons

Started by
39 comments, last by Way Walker 15 years, 2 months ago
Quote:Original post by M2tM
From personal experience they are best avoided, but when wrapping a c style library in a series of classes to enhance functionality I found it difficult to dodge a singleton. The special circumstances are that first, SDL_Mixer isn't really multi-instancable because it is based on several c functions which share a single state. And the second is that to implement a play list it seems you require a basic c style function pointer. At the time I knew of no way to cast between a class specific member function and a global c function, but I believe that mem_func would probably do what I need (though when I was having this issue nobody suggested it.)

In any case, it was a decent use of a singleton because the actual concept being wrapped could not safely have several instances without each instance knowing about the other ones so we knew if it was initialized and playing etc.

Nobody suggested a better alternative in this thread:

http://www.gamedev.net/community/forums/topic.asp?topic_id=520472
I dealt with this also while building a framework around SDL_mixer, but didn't use a singleton. The problem here (if you want to call it that), is that the class in question only meets one of the 'singleton' criteria: it would be an error (more or less) for there to be more than one instance.

However, the other criteria - that global access is needed (or even desirable) - doesn't really apply here. Under normal circumstances only a small percentage of game code will need access to the sound system; as such, I'd argue that a singleton isn't really an appropriate solution here.

I ended up deriving the 'sound system' class from a 'single instance' base class that throws an exception if more than one of the derived type is created, and used static functions where C-style callbacks were needed. Not ideal perhaps, but I do think it's a better solution to the given problem than a singleton (at the very least, it shows that there are other solutions to this sort of problem besides using a singleton).
Advertisement
Quote:Original post by Splinter of Chaos
Couldn't I consider my OS a singleton? (Host OS?)

No. A singleton is instantiated per process creation, while an OS is instantiated per bootup.
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.
Quote:Original post by jyk
Quote:Original post by M2tM
From personal experience they are best avoided, but when wrapping a c style library in a series of classes to enhance functionality I found it difficult to dodge a singleton. The special circumstances are that first, SDL_Mixer isn't really multi-instancable because it is based on several c functions which share a single state. And the second is that to implement a play list it seems you require a basic c style function pointer. At the time I knew of no way to cast between a class specific member function and a global c function, but I believe that mem_func would probably do what I need (though when I was having this issue nobody suggested it.)

In any case, it was a decent use of a singleton because the actual concept being wrapped could not safely have several instances without each instance knowing about the other ones so we knew if it was initialized and playing etc.

Nobody suggested a better alternative in this thread:

http://www.gamedev.net/community/forums/topic.asp?topic_id=520472
I dealt with this also while building a framework around SDL_mixer, but didn't use a singleton. The problem here (if you want to call it that), is that the class in question only meets one of the 'singleton' criteria: it would be an error (more or less) for there to be more than one instance.

However, the other criteria - that global access is needed (or even desirable) - doesn't really apply here. Under normal circumstances only a small percentage of game code will need access to the sound system; as such, I'd argue that a singleton isn't really an appropriate solution here.

I ended up deriving the 'sound system' class from a 'single instance' base class that throws an exception if more than one of the derived type is created, and used static functions where C-style callbacks were needed. Not ideal perhaps, but I do think it's a better solution to the given problem than a singleton (at the very least, it shows that there are other solutions to this sort of problem besides using a singleton).


I agree with you, the primary reason for the decision to actually make it a singleton was because I thought I needed a global access point in order to get an instance of my class from within the c global function callback it registered to. This then meant that it fulfilled both requirements (as far as I knew at the time).

That said, I believe it could be avoided with mem_func but I haven't implemented it yet. Provided that works as intended it would no longer need to be a singleton and I could enforce the single instance in a similar manner to what you describe.

Anyway, a round-about way of admitting I used a singleton because it seemed to be a good idea and it certainly isn't a terrible application for the pattern (indeed, it's a better candidate than most) but in reflection it may have been unnecessary and thus a better solution could be present.
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
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.


What he said. The problem with the Singleton is misuse. They are fine for making sure one instance exists, they can also help in cases where you need control over the order of instantiation of an object. Both of these are valid reasons to use a mechanism that helps with that.

However, it's a much rarer case where you need a global point of access to something. This is part of the singleton definition, but it is the controversial one too. Even if you do have that global point of access, as kyoryu says there is nothing to stop you passing the object around via dependency injection. This is valid because the code using the singleton often has no use for the knowledge of whether something is globally accessible and taking that into account does get you around the decoupling problems.

The problem with the singleton pattern is the lack of defence against misuse. It's very common to be misled by it, taking a path that initially looks like an easier one. Almost every C++ programmer has fallen for that one.

Also, don't fall into that laws of physics example. I know plenty of games that have been tweaked to be playable simply by fiddling with the physics on a level by level, object by object basis.
A global point of access is required for a singleton so that you can actually *find* the thing. If there's only one of the thing lying around, it must have a globally known access point, or you wouldn't be able to get to it.

It is not, however, a *feature* of a singleton, and the use of the singleton pattern shouldn't be based on the global accessibility. Control of instantiation (both number and timing) is the *feature* of the singleton.
Quote:A global point of access is required for a singleton so that you can actually *find* the thing. If there's only one of the thing lying around, it must have a globally known access point, or you wouldn't be able to get to it.
How so? I have a number of objects in my framework that are the only one of their type (a constraint that is enforced), but they aren't globally accessable; rather, they're created locally and then passed forward as necessary.

Or are we talking about different things?
Well, you could do that by making the class private, and inheriting from some base class, I guess, but at that point that class isn't particularly usable by anybody except that particular implementation.

I'd probably argue that what you're doing is closer to the "intent" of the singleton pattern than the common usage of it.

I'm basically asserting that the common usage of the singleton pattern (MySingleton::GetInstance()->... in all kinds of places) is really just a global with a pretty wrapper. 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 don't buy the anti-singleton statements on this forum. Yes, they can be misused, yes, there are alternate solutions to "solving" the problem, but find me something in programming that can't be misused or done differently. I don't see why singletons get any special attention.

If you want to use a singleton, I say go for it, just make an educated decision and know the pros/cons of your choice.
-- gekko
Quote:Original post by gekko
I don't buy the anti-singleton statements on this forum. Yes, they can be misused, yes, there are alternate solutions to "solving" the problem, but find me something in programming that can't be misused or done differently. I don't see why singletons get any special attention.

If you want to use a singleton, I say go for it, just make an educated decision and know the pros/cons of your choice.


The problem with them imho is primarily that they hide dependencies and you can get very obscure results with unrestricted global access and they are not multi-instancable which makes test suites with projects with many singletons difficult to run...

Most cases where people use a singleton there is no real reason why there can't exist more than one instance of the object, I had an example where it would be an error to have more than one instance, but even asserting that you have a true example of a single instance requirement the global access point is prone to enabling messy code and still hides dependencies.

Here is a decent video presentation of the case against Singletons.


I don't believe that they are evil, but before you use one make -sure- other possibilities have been exhausted and that the cleanest and best option is a Singleton.

See my comment for the highlight of the presentation:
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk

This topic is closed to new replies.

Advertisement