Public/protected/private is an unnecessary feature
Role of access modifiers
- Many commenters frame
public/protected/privateas tools to:- Mark what is stable API vs internal implementation.
- Reduce cognitive load when reading unfamiliar code.
- Signal who “owns” breakage when internals change (author vs user).
- Help compilers/JITs optimize (e.g., inlining, representation changes).
Arguments that private/protected are unnecessary or harmful
- Anything “private” can often be bypassed:
- Reflection, unsafe accessors, name-mangling tricks.
- Forking the library and removing/modifying access keywords.
- Preprocessor hacks or pointer tricks in C++.
- This leads some to argue privacy is mostly social signaling and should be a non-binding annotation (like TypeScript types or
@internal), or omitted entirely. - Strict enforcement can hurt downstream maintainers when vendors change visibility across versions, making upgrades painful.
- In contexts where you control the whole stack (e.g., backend services in containers), forking to expose internals is often seen as acceptable.
Arguments in favor of access control
- Library and framework authors rely on private/internal members to:
- Freely refactor internals without worrying about external dependencies.
- Prevent consumers from coupling to fragile details and accruing tech debt.
- In many settings (OSes, runtimes, proprietary apps, system libraries), consumers can’t realistically fork the dependency, so access control matters more.
- Even in non-OOP or inheritance-light code, marking internal functions/fields reduces convention-based ambiguity and naming games like
_DO_NOT_USEor_UNSAFE.
Soft vs hard privacy mechanisms
- Some prefer “soft” privacy:
- Python underscores and name-mangling; conventions over enforcement.
- Go’s package-private vs exported (capitalization-based) model.
- C#/Java internal/assembly/package-level visibility; namespace-based “internal” APIs.
- Common Lisp’s exported vs unexported symbols.
- Others argue that once annotations for privacy are standardized, they effectively become language features, so they might as well be enforced.
Inheritance, composition, and OOP context
- The original article’s stance is tied to a broader “inheritance is an antipattern” view; several commenters reject this.
- Many see private/protected and inheritance as valuable for:
- Partial implementations in base classes.
- GUI frameworks and other extensible systems where subclassing is common.
- Others push for composition, traits/protocols, and FP-style patterns instead, but concede that pure composition can become verbose and awkward.