It's not so much a matter of trust, but rather one of managing complexity.
A public member can be accessed from outside the class, which for practical considerations means "potentially anywhere". If something goes wrong with a public field, the culprit can be anywhere, and so in order to track down the bug, you may have to look at quite a lot of code.
A private member, by contrast, can only be accessed from inside the same class, so if something goes wrong with that, there is usually only one source file to look at. If you have a million lines of code in your project, but your classes are kept small, this can reduce your bug tracking effort by a factor of 1000.
Another advantage is related to the concept of 'coupling'. A public member m
of a class A
that is used by another class B
introduces a dependency: if you change m
in A
, you also have to check usages of m
in B
. Worse yet, nothing in class A
tells you where m
is being used, so again you have to search through the entire codebase; if it's a library you're writing, you even have to make sure code outside your project doesn't break because of your change. In practice, libraries tend to stick with their original method signatures as long as possible, no matter how painful, and then introduce a block of breaking changes with a major version update. With private members, by contrast, you can exclude dependencies right away - they can't be accessed from outside, so all dependencies are contained inside the class.
In this context, "other programmers" include your future and past selves. Chances are you know now that you shouldn't do this thing X with your variable Y, but you're bound to have forgotten three months down the road when a customer urgently needs you to implement some feature, and you wonder why doing X breaks Y in obscure ways.
So, as to when you should make things private: I'd say make everything private by default, and then expose only those parts that absolutely have to be public. The more you can make private, the better.
The modern consensus is that you should not do this at all.
Having a 'all instances of this class' design has proven to be troublesome in many aspects, the foremost being with regards to concurrency. Do you want all widgets, or all widgets owned by your thread? Do you really want to make that all widget list threadsafe? Remember that unit tests are almost always done in parallel, so "my app is single threaded" might not be good enough.
The other problem you run into is in your design. With the 'one and only' list of anything, be it global, static or singleton you'll quickly run into issues when you need more than one. You'll run into issues with temporary widgets or offscreen widgets if they're automatically added to the list. You'll run into errors where you forgot to add them to the list if they're not automatically handled.
Once you don't have the 'all instances of a class' requirement, then you end up with a plain old collection. Whatever consuming code is working with the widgets (even if that's some framework that is in turn consumed) can orchestrate how the collection is used and how/when the widgets get put in there. The widgets themselves should not care.
Best Answer
Global variables are never necessary unless you are interfacing with existing code that imposes unsuitable constraints.
One alternative is to make the dependency explicit:
1. Create a class that describes the purpose of this shared data. Without knowing your problem domain, I'm going to call it a
Counter
.Note that wrapping the variable through accessor functions allows us to impose checks and constraints. This lack of checks is one major problem with exposing variables directly.
2. Use some dependency injection mechanism to supply a
Counter
instance to all classes that need it. For example, we can use constructor injection:The counter is created in some initialization code (like your main() function) and then provided when the dependent classes are instantiated:
All global variables have a similar instantiation, but it's just done implicitly during class loading. By managing the initialization ourselves we gain a lot of flexibility:
ClassName
functionality is reused in a different context.If you cannot make these dependencies explicit, at least encapsulate the variable using static methods in a similar fashion.