The core objection
The accepted answer builds it carefully. If two components share a mutable global, then knowing the state of the system before a call is no longer enough to predict the result, because something else may have changed it in between. Predictability is not an aesthetic preference — it is the property that lets you reason about a piece of code by looking at it, and the property a test depends on to produce the same answer twice.
What follows from that
- Bugs that can originate anywhere. Mutation from any point in the program means the cause of a wrong value can be arbitrarily far from where it surfaced.
- Tests that need setup. Every test has to arrange the global state first, and has to restore it afterwards or contaminate the next one.
- Hidden dependencies. Nothing in a function's signature reveals that it depends on the global, so the compiler cannot warn you and a reader has to go looking.
Why it gets worse over time
One answer made the point about maintenance rather than correctness. Because anything in the program may be using it, a global becomes progressively harder to remove — and any change to it potentially requires changes everywhere. Finding the callers is not the difficulty; the difficulty is that there is no boundary limiting how many there can be. It is a decision that becomes more expensive to reverse the longer it stands.
The distinction worth keeping
- Mutable global state is the target of every objection above.
- Global constants share none of these problems, because nothing can change them between one call and the next.
- The practical rule the thread points at: if it is shared and it changes, pass it explicitly so the dependency is visible.