Arc<RwLock<T>> fits the bill. Just pass it around. Additional plumbing isn't the end of the world.
Arc<RwLock<T>> fits the bill. Just pass it around. Additional plumbing isn't the end of the world.
(I actually want to write a blog post about this... haven't done so yet though. People reach for static too often and thread_local! too little, IMHO. Of course, not needing either is best.)
That is, too many people skip straight to static without even considering TLS, not that they should be using TLS more often in general.
(I've seen way too many times a thread-local being used as a way to smuggle extra parameters, often through several layers; inevitably, this breaks when one of the intermediate layers decides to run things in a separate thread pool.)
At some point, you see enough of this that you realize the tool is more dangerous than helpful. The makers of Kotlin and many other newer languages seem to know this and have disabled inheritance as a default or left it out entirely.
It's always easy to spot in hindsight, but TBH I think the threshold for creating interfaces or base classes should be a bit higher - likely when you know you will need 3 or more implementations. It's always felt like premature optimization to me, unless something is hard coded to only accept an interface like using Type.IsInterface or something.
Concepts like "Product" are almost always going to have multiple implementations though, so it's easy to judge in that case to make an interface/base class at the beginning. The real magic is guessing what other concepts satisfy this requirement.
This can happen between different layers of app. For example you might have a persistence layer under an API or UI, and want to expose a nice "clean" interface to the API / UI layer.
To add to that, in C++ that approach often saves non-trivial amount of compilation time. Consumers of the object only need to #include the interface, while the implementation of the object, both code and data, stays private and is not needed to compile the consuming code.
That's not a OO problem, that's a software engineering and code quality problem.
Modularity/compartmentalization and the obligation of managing complexity are basic age-old principles. You'll arrive to a big ball of mud if you are oblivious to these basic principles, whether you do inheritance or composition.
Don't pin the blame on a programming paradigm if your developers are clueless about basic software engineering principles.
You can write OO code without inheritance. Inheritance is syntactical sugar, essentially. You can accomplish the same things with interfaces and composition.
The difference between composition and inheritance is that a composed method is fully discoverable. I can see every statement. There's no secret parent method running before or after.
It's not the end of the world, but it's unnecessary and avoidable pain.
A singleton is not a OO pattern, it's a memory access pattern.
It's high time people stop parroting cliches and start to look at patterns as what they are: typical solutions to meet recurring requirements.
A singleton is just a way to ensure a single object is instantiated and exists system-wide. That's it. It's a global object, attached to a negligible (and thus often ignored) requirement to not allow instantiating other objects of the same type.
One way to implement singletons is to get a static function return a static variable. No OO required.
It's all about memory access. Single variable used to store global state. That's it.
Additionally, "memory access pattern" does have an established definition (which you may also be opposed to), and you may confuse people with your usage of it.
The argument is self-evident. A singleton does not use or need any OO construct to be implemented or used.
There is nothing special or specific to OO to exclusively own the concept of ensuring a single globally-accessible system-wide data structure.
As I've said, singletons are implemented with static functions returning static variables. No OO involved at all.
Your only argument tying singletons to OO is the fact they are covered in GoF. However, that argument has no merit not makes any sense. GoF does not specify what is and is not OO. It only shows basic design patterns and presents ways of implementing them with OO languages. Otherwise you would also claim that instantiating variables is OO just because GoF describes factory methods.