5 ms·
> But these are all very convoluted compared to having a single class-method in the class itself which returns a shared (static) object. I used to think the sa
by jarrett 13y ago
> But these are all very convoluted compared to having a single class-method in the class itself which returns a shared (static) object.
I used to think the same thing. But lately, I've come to think it's better for code to explicitly reveal its dependencies via its public API. If class Foo uses the singleton class Bar, you can't see that dependency just by looking at Foo's API.
My preferred solution in OOP is either: a) have Foo's constructor accept a reference to an instance of Bar, or b) for any method on Foo that requires a Bar, have that method accept a reference to an instance of Bar. I find this disciplined approach helps me reason about my code and understand how units of code relate to each other.
I only developed this insight after diving into functional programming. Prior to that, I was all about convenience. Singletons were convenient, and I didn't want to pass a references around all the time. It seemed like a lot of pointless ceremony. Now I've changed my tune. Rather than pointless ceremony, it's a form of self-documentation.
- sdegutis 13y agoWhat's the benefit of doing it that way? The only one you mentioned is self-documentation, but that seems like a weak argument against these kind of singletons. It sounds like you're giving up the convenience of singletons solely for the sake of not having singletons, which seems pointless in itself.
- stcredzero 13y agoI read that as not having singletons for the sake of self documenting code dependencies. In a way, a singleton is a "magic" dependency that can reach into the middle of your code without a trace. By always passing it in, you're making it explicit. This is the same as the pure functional discipline of having all values passed in, never coded into a function.
- evanspa 13y agoThis article echoes the same idea (instead of big singleton, view controllers should accept the data they require in their initializer (constructor)) and gives some reasons why to do it this way: http://www.hollance.com/2012/02/dont-abuse-the-app-delegate/ http://www.hollance.com/2012/02/dont-abuse-the-app-delegate/
- sdegutis 13y agoThis is mostly an argument against making AppDelegate into a God object, which I totally agree with. It's not saying singletons themselves are inherently bad. It does generalize saying that they usually make it difficult to evolve an app's internals, but I disagree with that. As long as they're chosen when appropriate, and used properly, there's no problem.
- usefulcat 13y agoTestability.
- Hermel 13y agoBingo. If you want to test class Foo in isolation, it is essential to know that it depends on Bar. Furthermore, when taking testing seriously, you might want to test Foo's behaviour in combination with differently configured instances of Bar - which is only possible if Bar is not a singleton.
- jarrett 13y agoI'm giving up singletons because hidden dependencies are a source of bugs. Let me make it more concrete: Suppose classes A, B, and C use singleton class S, and S has state. Via the hidden dependency on S, it's possible for A, B, and C to affect each other without explicitly calling each other's methods. As a programmer, you can take those hidden interactions into account and still have a relatively bug-free program. But it's one more thing you have to hold in your head. When you return to the project six months later, you have to read through the internal code of A, B, and C to see these interactions; the public APIs don't reveal them. You spend more time figuring out how the objects interact, and there's a greater chance you'll fail to notice an interaction.
- sdegutis 13y agoIn the general case, I agree. But for a very few things, singletons make fine sense. Usually in small programs where you can draw the entire object graph on a single piece of paper, and where all the features it will have are known up front.
- jarrett 13y agoCertainly! Tiny programs are the exception to most best practices. (Not security best practices, but I digress.) I write a lot of little programs, and they're certainly not all works of art. Sometimes you need to bang out a tiny program quickly, and it's never going to become a maintenance burden. In which case you can use any pattern or anti-pattern you like.
- sdegutis 13y agoThat sounds like a very black/white way to say it. I don't agree that using a singleton in small programs is an anti-pattern. The world is much more gray than that.
- jarrett 13y agoI said you can use anti-patterns in small programs, not that singleton is an example of an anti-pattern. I don't believe singleton is so terrible as to be an anti-pattern, even for big programs. I just think it has some downsides that are really worth considering before you use it.
- fauigerzigerk 13y ago>But lately, I've come to think it's better for code to explicitly reveal its dependencies via its public API. The downside is that you're forcing a new dependency on the user of your API, and that dependency may be an implementation detail that the user should not be concerned with. You could argue that the user was already depending on that singleton because singletons are effectively globals. But that's not necessarily true as the singleton could have package/module visibility. I'm not convinced that all encapsulation should be sacrificed on the altar of TDD.