I agree that it's unnecessary, and Python's success despite not having private members/fields is testament to that. But public/private fields/methods, like pretty much everything in OOP, is a 'social' rather than engineering innovation. Just as a class tells you certain operations and data are inter-related, private methods or fields signal to a class's users that you probably will break things if you interfere with certain parts.
Otherwise, at least in C++, you can often bypass the private specifier without much difficulty. Perhaps the laziest and easiest way to do so is
#define private public
#include "foo.hpp"
#undef private
Pretty much all language features save for a shockingly small set are "unnecessary". The proper question is "are they useful?"
The usefulness of public/protected/private is that it provides a way to narrow the surface area through which derived classes can interact with their superclasses. Which is enormously useful from a maintenance perspective.
The place where inheritance is better than composition is where base classes provide partial implementations that are used by derived classes.
> 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.
Together with classical refactorings (extract method, move method, extract class), they're a precious tool.
Of course, typing is a consideration as well, but I'm talking exclusively about their role in granularity control.
It is unecessary, but convenient. It can be misused. Composition can also be misused.
Do you really want to create an interface for every possible place where you'd use `private` though?
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.
Locking away backing fields from a property is not an unnecessary feature.
I'd like them extended slightly, in fact. I'd like a friend declaration after an access specifier to apply only until the next access specifier. Eg.
class Foo {
public:
void method_A();
protected:
friend class Bar;
void method_B();
protected:
friend class Baz;
void method_C();
private:
void method_D();
};
anyone can call method_A(), only Bar can call method_B(), only Baz can call method_C() and nobody can call method_D().You can do this by inheriting from 2 different pure abstract classes, but that feels much kludgier to me.
In Common Lisp, we sort of get this by the separation of exported versus unexported package symbols.
Unexported package symbols do two things:
- when visibility "windows" are created between packages via the "use" mechanism, unexported symbols are excluded.
- unexported symbols require tokens with two colons: you have to write foo::bar, not just foo:bar, to refer to bar if it is unexported from package foo; moreover you must still write foo::bar even if you are using package foo, whereas if it were exported, you would just write bar.
CLOS uses symbols for naming entities like generic functions, classes and slots. It has no additional protection mechanisms beyond what the symbols provide, and symbols are agnostic of classes (and everything/anything else which they name).
Access modifiers don't give you unlimited protection, they help you reason about the code and how it is used. If I change a public method and break something downstream, that's on me and my team. If I change a private method and break someone else's code which was bypassing using reflection or other mechanisms, that's on them.
Languages like Python don't have keywords but enforce using conventions like underscore and 'dunder', the latter of which is actually enforced using obfuscation. It is extremely helpful to signal to users that they should not be using certain methods or fields. When there are no access modifiers available, we still see teams writing methods like "xyx_UNSAFE" or "abc_DO_NOT_USE". It's ridiculous to me to encode this kind of information like this instead of having first class support in the language.
Access modifiers also tell the compiler or JIT what is safe or unsafe to manipulate. It has implications beyond users, and can be a determining factor when inlining or making other optimizations.
This article is so opinionated (edgy?) that it ends with "Inheritance was a hack in the first place." I think, like all things, we need to consider the broader landscape for object oriented programming instead of just saying these things are irrelevant and absurd and useless.
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…).
Please don't fall for the clickbait here. Take a look at the history of posts from this site.
OOP is the unnecessary feature that can be replaced with interfaces/traits and composition and proxy pattern. OOP is excessive convenience that led to numerous non-orthogonal features in many languages.
For most modern languages, something like an @internal annotation would work better. With compiled languages that need to conform to an ABI or export RPC definitions, there is merit to specifying what exactly must be exported (or must never be inlined), but even that could be tackled by an @internal or @nodoc or @private annotation - not a language construct.
See also https://steve-yegge.blogspot.com/2010/07/wikileaks-to-leak-5...
https://steve-yegge.blogspot.com/2010/07/wikileaks-to-leak-5...
Brilliant steve yegge article on the topic.
Wikileaks To Leak 5000 Open Source Java Projects With All That Private/Final Bullshit Removed
On a more serious note. While I can see the reason for private members, the case for private methods has always been much weaker.
Of course they are unnecessary, but then strictly speaking control statements can be omitted in favor of goto statements. Are they unnecessary?
Quick note that inheritance existed in assembly language programming (and programs written using the front panel switches if you want to take things to the limit) and were not "invented" in Simula or C++. Those languages invented syntactic sugar for techniques that were quite mature at the time both in assembler and older HLLs such as BCPL and C.
OOP and interfaces are at a bit of tension.
With inheritance, you’re breaking some level of encapsulation by choice; it needs to be done carefully.
Likewise, the base class needs to be designed thoughtfully.
"Because you can limit visibility with interfaces, limiting visibility without using an interface is unnecessary."
No thanks. And I'll continue using inheritance and composition correctly too.
IMO, the Go model of package-private and public entities is the best compromise. Simply because it reduces the global namespace pollution.
Is so the IDE doesn’t show up stuff when private
Honestly, subclassing strikes me as mostly unnecessary. Most of those use cases can be addressed with protocols or traits.
Ah the good old “xxx considered harmful”
Also the static members of a “class” are another interface: a distinct interface that also enforces a singleton.
now say it in a sociology or economics conference
All private does is make it hard for developers further down the track to make changes that they want to make.
And if you don't need private then why have public?
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...
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).