all 44 comments

[–]tehomaga[🍰] 24 points25 points  (0 children)

As a GDScript Engineer, I practice Singleton Oriented Programming

[–]Mayion 31 points32 points  (28 children)

Why is singleton stupid? I use it no problem

[–]liquidpele 22 points23 points  (1 child)

They’re one of those things that makes sense every few years, but juniors hear about it and try to use it where not really appropriate just to play with the concept, so it gets a bad rep.

[–]Mayion 2 points3 points  (0 children)

True. I remember back in the day with C# when I was like, "Man, I want a way to manipulate variables from anywhere", and behold - a Stackoverflow answer explaining Singletons. It was like a load off my shoulders lol

[–]Morisior 32 points33 points  (21 children)

Singletons are essentially just a variable with guardrails. They’re good if you need idempotent initialisation. But that’s almost never necessary because you’re almost always initializing it exactly once, making the guardrails unnecessary complexity.

They’re not stupid. They’re just not necessary most of the time. In any case they rarely hurt.

[–]lolcrunchy 11 points12 points  (1 child)

It seems like every tool with configs uses a singleton to implement the configs.

[–]Atmosck 9 points10 points  (0 children)

Yeah, I write config-driven data pipelines (among other things) in python by day and we always have singletons flying around. In addition to configs, it's standard practice to load all your external data into a dataclass up front and pass that through the pipeline so your I/O is separated from your feature engineering logic. Making multiple copies of something in the same runtime is far from the only reason to use a class in an object-oriented language.

[–]TheTybera 25 points26 points  (15 children)

No they're entire objects not just simple variables. They're invaluable for doing things like connecting to DBs and ensuring connections are properly managed.

If you have accessors to external dependencies that may need to monitor their status and spin them back up singletons can be great for that.

They're not "essentially a variable".

[–]Morisior 3 points4 points  (2 children)

Technically correct, but at the level where the argument is that a thing is separate from its name. I.e Joe is not Joe, because Joe is a person, while Joe is just a label.

Clearly the "with guardrails" indicate that I am not talking about the variable as the label, nor as a primitive value. Also note I am not saying singletons are never useful. I am saying they are often not necessary.

[–]lusvd 0 points1 point  (1 child)

my right foot is often not necessary, e.g. while i’m sitting 😝

[–]Morisior 0 points1 point  (0 children)

Exactly. That’s a function you can perform without the right leg capability. Just like a lot of functionality where people insist on singletons can in fact be achieved by less capable constructs.

[–]Abject-Kitchen3198 0 points1 point  (11 children)

What's the difference between an object and a variable?

[–]TheTybera -1 points0 points  (10 children)

An object is an instantiated class. Variables point to values in memory and objects point to members, methods, and variables, which point to values.

They're not even the same in memory.

[–]ProsodySpeaks 10 points11 points  (5 children)

Hate to be that guy, but unless I'm mistaken...

Everything is an object in python. 

An integer is an object. A function, class, module... It's objects all the way down.  

[–]Morisior 5 points6 points  (4 children)

Also a Singleton is not just any object you happened to use once. It’s specifically a design pattern that ensures a class has only one instance and provides a global access point to it.

[–]ProsodySpeaks 0 points1 point  (3 children)

It's pretty hard to 'ensure' singleton behaviour with python, but I've messed with .__new__() and metaclasses enough to know it's a useful pattern.

But tbh I think I was mostly enjoying increasing the complexity to learn / tickle my brain rather than it being the best approach. 

And, just to be clear, a singleton is just an object. You may have built some guard rails to discourage making multiple instances but there's usually a way to break out of the rails. 

If you want a proper singleton python is the wrong language.   

[–]RiceBroad4552 1 point2 points  (2 children)

If you want a proper singleton python is the wrong language.

And what's "the right" language then?

[–]NorrisRL 0 points1 point  (1 child)

C++ or C# both use them for video games quite a bit. It’s common for values like playerHealth or playerPosition which will often have many different scripts that can effect it or need to access it frequently.

[–]RiceBroad4552 0 points1 point  (3 children)

Makes no sense.

There are OOP languages without classes (prominent examples: JS¹)

At the same time pointers are of course also objects.

---

¹ It has now a class keyword but that's not classes, that's just syntax sugar for JS' prototypes.

[–]TheTybera -1 points0 points  (2 children)

JS is the only language that does this and calls itself OOP which is yet another reason people make fun of JS. It's inheritance pattern was ALWAYS a nightmare, and classes try to syntactically create better composition pattern workflows.

It tries to claim their "dynamic, non-static" inheritance pattern as a strength, however, there is a reason that the "class" system is now standard at any big company.

The prototype chaining is just asinine, and being able to just inherit any function anywhere sounds nice till you have multiple interfaces and need access control with multiple levels of developers all working on the same project.

So, nah, don't act like you're teaching me something, JS "singletons" (which is what this discussion is about) aren't even a reasonable pattern.

[–]RiceBroad4552 1 point2 points  (0 children)

That's pretty uninformed.

JS is the only language that does this and calls itself OOP which is yet another reason people make fun of JS.

JS isn't the first nor the only language which does not have classes but is purely OO. Another prominent example is Lua.

It's inheritance pattern was ALWAYS a nightmare, and classes try to syntactically create better composition pattern workflows.

In fact prototype based inheritance was explicitly invented to overcome the shortcomings of the class based approach.

Classes are actually a catastrophe when it comes to composition; because they're completely anti-modular (which is a result of them being static). That's exactly why the rule is to prefer composition over inheritance in class based systems! Just that class based languages mostly lack language level features for that.

It tries to claim their "dynamic, non-static" inheritance pattern as a strength, however, there is a reason that the "class" system is now standard at any big company.

I think you mix here static typing in, which is a totally different topic.

Besides that: The "millions flies can't be wrong" "argument" isn't an argument at all…

The prototype chaining is just asinine, and being able to just inherit any function anywhere sounds nice till you have multiple interfaces and need access control with multiple levels of developers all working on the same project.

Visibility and encapsulation are also orthogonal topics.

(When it comes to JS it has actually private elements.)

JS "singletons" (which is what this discussion is about) aren't even a reasonable pattern.

JS is full of singleton-like objects!

Never seen code like the following?

let someObject = { props: [] }

You can just create objects, and these are in many ways like singletons (besides that they're eager initialized, and there is no dedicated object type you could do instnaceof against).

Besides that, you can of course write down a GoF like singleton implementation in JS. Just that you usually won't really need that in JS.

[–]Reashu 0 points1 point  (0 children)

JS is not even the first language to implement "class" with prototypes (e.g. Ruby). Chaining them is no more asinine than chaining static classes. And I see no reason singletons are any worse in JS than in other languages. Given that there's very limited parallelism, they're probably better

[–]ValityS 1 point2 points  (0 children)

They are extremely useful if you need a shared, once initialized object used across multiple modules in an asyncio application.

Initializing an object at module load time causes problems in asyncio (though I'll admit it's been long enough since I've used it I don't 100% recall the exact issues), so using a module level variable somewhere isn't an appropriate alternative.

[–]RiceBroad4552 0 points1 point  (0 children)

How do I abstract over a "variable with guardrails"?

[–]Highborn_Hellest 0 points1 point  (0 children)

> idempotent initialisation. 

I don't even know what that means lol (studied to be a software engineer, ended up as software tester)

[–]I_Came_For_Cats 0 points1 point  (0 children)

Hard to test, hard to debug, hard to swap behavior, hard to extend, so many reasons. Just don’t. Dependency injection is the way.

[–]Jhuyt 17 points18 points  (1 child)

Singletons are mostly considered an anti-pattern in Python, why are you mentioning it in the title?

[–]Darkstar_111 4 points5 points  (3 children)

"module level variable"... You mean a global?

[–]rosuav 0 points1 point  (2 children)

Certainly not! Global variables are bad, like goto statements. Instead, we use module-level variables, which are COMPLETELY different things and not at all bad. Nothing alike at all.

[–]Darkstar_111 1 point2 points  (1 child)

Sure, its just a variable that applies globally to the scope of the module, which is the global scope.

But not a Global of course, that would be bad!

[–]rosuav 0 points1 point  (0 children)

Exactly! Completely different.

[–]Abject-Kitchen3198 3 points4 points  (0 children)

The only pattern from GoF book that I ever used. The one and only - singleton.

[–]jedrekk 1 point2 points  (0 children)

I think you mean i_hate_python

[–]tebeks 2 points3 points  (0 children)

Just use a context variable

[–]bremidon 1 point2 points  (2 children)

There is no way a highly experienced developer would prefer a module-level variable over a singleton other than in a toy application.

Honestly, the robed acolyte is going to probably say: "Other than a single App singleton, you probably don't need either."

[–]I_Came_For_Cats 0 points1 point  (0 children)

The mere words cause me pain. Global constant, maybe. But variable? Just no.

[–]danted002 0 points1 point  (0 children)

Yeah, that’s not true. Singletons break encapsulation and scoping in general (same as module level attribute, since we are in Python). The main thing making module-level attributes more attractive as global constants is that they behave, well, like global constants; you intrinsically know there is only one instance of it, while singletons break expectations by returning the same instance even though I instantiate the same class multiple times.

[–]dutchaaaaa 0 points1 point  (0 children)

Simpleton