Public/protected/private is an unnecessary feature
18 comments
·June 17, 2025jonathanlydall
kevingadd
I also wish 'sealed' was the default for classes in templates. Usually you're not thinking about what will happen if someone shows up 5 years later to derive from a random class you created, and it has performance benefits to seal a type. You can always remove the sealed qualifier later on purpose.
null
ctxc
Do you really want to create an interface for every possible place where you'd use `private` though?
WorldMaker
Right, even if it is just syntactic sugar for a "pure" dual of `interface` as the article posits, syntactic sugar still has advantages/merit in many scenarios.
ctxc
Exactly. Ime most classes are not designed to be inherited but want to expose a clean public API.
While true that all classes can be inherited, treating _all_ classes with the assumption that they will be would just lead to a labyrinth of code.
Dwedit
Locking away backing fields from a property is not an unnecessary feature.
scotty79
If somebody needs access to the backing field it's usually for a good reason. And if you restrict it, they'll just fork your code and overwrite whatever they need.
It should at most be a soft annotation to prevent it from getting auto-completed, not a restriction.
derefr
You're assuming a very simplistic model of API coupling, where there are only "applications" and "libraries that the application compiles into itself." But:
• There are also runtimes, installed separately from the application. You might be able to fork the JDK, but people want to run your Java application on their JRE, not yours.
• There are proprietary applications that nevertheless expose APIs to code against. A Photoshop plugin author can't fork Photoshop to expose fields of the plugin host.
• There is the OS itself. You can fork the Linux kernel (and gcc/clang) to expose some internal data your application needs as a system call — but unless you get all that code upstreamed, your application is now entirely non-portable, running only on your own servers at best.
• Most commonly of all, there are system libraries. You can certainly fork (and co-distribute / bake in) a library like libicu or libxml — but no major OS will be willing to ship your app or lib as a system package of its own, if it does that. They'll want your app/lib to depend on the existing packaged version of those libs.
None of this matters, of course, if you develop proprietary-service backend software for a living. You can maintain a menagerie of weird lib forks, shove all the build artifacts into a docker image, and it'll work for you. But much (I'd say the majority) of the world's programming is not in proprietary-service backends, and so needs to actually depend on code it doesn't control.
magicalhippo
I like Boost's approach[1] of using a separate namespace for these implementation-specific things, rather than visibility modifiers.
Then the internals are accessible if you need it for a temporary workaround or such, but it's also very obvious when you are accessing stuff you really shouldn't. And implementers are still free to rearrange the internals as they see fit.
[1]: Not saying Boost invented it, just where I saw it first.
tenebrisalietum
and then they also own future responsibility for that change.
baobun
In case one is not familiar with the author, they are commonly arguing that inheritance is an antipattern that should not be used in OOP languages. The OP is in that context: private and protected are not useful if you don't have inheritence.
alganet
> Use composition instead. Inheritance was a hack in the first place.
Composition is great. It's the preferred way.
However, if you take it to the extreme (composition only, never inheritance) you sometimes end up with really weird meaningless objects that have only a single method and a one-to-one relationship with another object.
Private methods are ideal for making those abstractions easier to understand. A private method, therefore, is equivalent to an object that has a one-to-one relationship with another object (it's only composed there) and a single method.
A protected method is similar, but allows whoever subclasses it to replace that single one-to-one "mini object" inside with another one-to-one "mini object".
When used within this mindset, it greatly simplifies code. It lets you simplify a branch that has only a single leaf into something easier to read.
It is unecessary, but convenient. It can be misused. Composition can also be misused.
jimbob45
I wish private was a suggestion and not strictly enforced in the same way that types aren't strictly enforced in C. Microsoft loves to make public variables private years during upgrades and it can be impossible to rewrite your application to avoid using that now-inaccessible variable. Looking at you, ASP.NET to .NET Core upgrade...
kevingadd
Have you heard of Unsafe Accessors? https://learn.microsoft.com/en-us/dotnet/api/system.runtime.... They help solve this problem.
ziml77
[delayed]
xyst
They are also optional in some languages :)
A long time ago in Java corp world, teams would create their own integration libraries with suspicious/horrible contracts. Ended up just using Java’s reflection api to update access modifiers to get their shitty library to work until they fix it (months later…).
deepsun
Or introduce a corporate rule to make everything public, if restricting didn't work anyways.
I primarily work in C# and access modifiers allow me to constrain which types or their members on it are accessible to other types or assemblies.
This is particularly useful when authoring libraries as I know that for anything not public, I can refactor to my hearts content (provided the externally observed behaviour is otherwise unchanged).
It’s a bit of a pity that it was only relatively recently that Visual Studio changed the template for new classes to use internal instead of public.
There are lots of public classes in codebases I work on which are probably only public due to the old default and not used externally so could be refactored, but it’s hard to be sure.
Whereas with internal classes I can be sure (unless someone has used reflection, but then that’s their problem).