29

Some modern languages (e.g. Swift, Dart) do not support the protected access modifier keyword. Swift is a protocol-oriented language, but I've heard that Dart is a completely object-oriented language.

Why don't these modern languages ​​support protected? Do you only need private and public for complete object-oriented programming?

I think it's convenient to have a protected access modifier keyword when there are some data or interfaces that I want to pass from the parent class to the child class. Why do some modern languages not support protected?

dandan78
  • 107
  • 5
ShutUpILoveYou
  • 423
  • 4
  • 5
  • 22
    No, `protected` is not required. You said it yourself: it is a "convenience." – Robert Harvey Dec 02 '19 at 01:52
  • 58
    OOP doesn't need private/public either. Many OOP languages works perfectly fine without public/private access modifiers. – Lie Ryan Dec 02 '19 at 10:36
  • 5
    @LieRyan, original OOP languages were designed with all data being `private` and all methods being `public`. – user28434 Dec 02 '19 at 15:00
  • 2
    If you look in a book on the _theory_ of Object-Oriented Programming, e.g., [A Theory Of Objects (Abadi, Cardelli)](https://www.amazon.com/Theory-Objects-Monographs-Computer-Science/dp/0387947752) you will not find _any_ mention of `protected`. Nor `private` or `public`.. They're just not part of object-oriented programming. They're part of _software engineering_, added to O-O programming _languages_ so that the compiler can help the programmer achieve "proper" O-O design practices. – davidbak Dec 02 '19 at 18:50
  • 10
    *Access control** modifiers are not needed for OOP *at all*, they solve a *different*, yet related, set of problems. – Polygnome Dec 02 '19 at 20:36
  • 4
    Python doesn't have private or protected. I feel that this example is something that shouldn't be forgotten from your list. – UKMonkey Dec 03 '19 at 11:54
  • 1
    Varying amounts of underscores are the best way to indicate private-ness. – GammaGames Dec 03 '19 at 17:16
  • 2
    Some languages even do not have access control at all... Access control is *orthogonal* to the programming paradigm. – Willem Van Onsem Dec 03 '19 at 18:36
  • @WillemVanOnsem That's true for `public` and `private`, but `protected` -- while it is an access modifier -- has no meaning without inheritance. – Zev Spitz Dec 03 '19 at 21:45
  • 2
    Regarding Swift, it has `internal` for module access, `fileprivate` and `private` for file level access. The combination replaces `protected` pretty well. Java doesn't have `fileprivate` but it's not any less OOP than Swift. – Sulthan Dec 04 '19 at 14:54
  • There's an official Swift blog post about this: https://developer.apple.com/swift/blog/?id=11 – Alexander Dec 04 '19 at 16:36

9 Answers9

46

It depends on what you mean by "required".

Access modifiers are not a necessity. You could replace every access modifier with public and most applications will work just like they did when you used varied access modifiers, proving the point that the compiler's main goal (outputting a working application) is not directly dependent on access modifiers.

As Delioth mentioned in the comments, both Javascript and Python are capable of OOP yet have no concept of access modifiers; proving the point that OOP does not require access modifiers.

However, access modifiers very much matter from a developer's perspective if you're interested in avoiding mistakes. Lack of access restrictions leads to developers accessing dependencies directly that they shouldn't (e.g. circumventing a validation/authorization layer), and this is going to lead to bugs, which leads to time and effort spent.

In conclusion, access modifiers are not required for the compiler, but they are mostly considered a very-nice-to-have for good practice. Such guidelines "require" developers to exercise diligent access control - even if the compiler doesn't need it.

Why some modern languages remove the protected?

There is no universally applicable answer to that question, other than "because that's what the language designers decided to do".

Flater
  • 44,596
  • 8
  • 88
  • 122
  • 4
    And for an example of not needing access modifiers: See Python or JavaScript; everything is public since neither language supports access modifiers, and both support OOP. – Delioth Dec 02 '19 at 19:31
  • @Delioth Good point. Updated my answer to include your comment. – Flater Dec 03 '19 at 07:12
  • @Delioth Though it should also be noted that both support hiding implementation details through closures, which are equivalent to private members (just like all locals are). But we've been using Javascript for OOP and functional programming for ages before anyone bothered using closures to hide "privates", so I'd say it definitely still counts. – Luaan Dec 03 '19 at 08:23
  • I am pretty sure that if you made all method public in `class A { private final void meth () {} } class B extends A { private void meth () {} }` compilation would fail. Have not actually checked it though. – emory Dec 03 '19 at 18:40
  • @emory: Sure, but that is quite the edge case where you've been hiding conflicts using access modifiers. Im no Java dev but C# does allow you to use the `new` keyword to effectively do what you're trying to do in your example - which does pass the compiler when everything is public. – Flater Dec 03 '19 at 19:39
  • If you replace every access modifier with _public_, your application will only function the same if you do not have any application logic based on access level. I have on occasion handled certain forms of business logic based on the access level of class properties (e.g., filtering which properties to include when exporting an instance of a class to some format or other), and that would break if all properties were changed to public. – Janus Bahs Jacquet Dec 04 '19 at 00:15
  • _"You could replace every access modifier with public and most applications will work"_. This is not an argument for me. Following your logic further one can say that "we can refactor OOP completely into one gigantic function call and everything will work". – Agnius Vasiliauskas Dec 04 '19 at 09:30
  • @AgniusVasiliauskas: The point I'm trying to make is that lack of public access modifiers in an otherwise OOP codebase doesn't inherently make it a non-OOP codebase. In other words, access modifiers are not an inherent requirement of being OOP. Your counterexample inherently isn't an OOP codebase from the get go, which is off-topic for the question at hand. – Flater Dec 04 '19 at 09:40
  • But it will be less-OOP'ish after removing protected feature. Still, I don't agree on your view. Following your logic,- let's just leave plain class'es without inheritance at all. We will make manual inheritance at object level, passing it to other class constructor and with the help of object cloning. Hell, we don't even need a constructor, let's just implement it ourselves with singleton model and a static method. At the bare level of ideas this programming style can be called "OOP-like", but is it really makes sense ? Once we add feature to OOP - it should stay forever. – Agnius Vasiliauskas Dec 04 '19 at 10:04
  • @AgniusVasiliauskas: You seem to be arguing that access modifiers have a purpose and should be used. I wholeheartedly agree. There are many reasons to use access modifiers to massively improve code quality. But access modifiers are not **required** for the core definition of OOP. You can have an (admittedly not as high quality) OOP codebase without access modifiers. Access modifiers and OOP are two separate concepts. Both of them are useful, but that doesn't make one dependent on the other. – Flater Dec 04 '19 at 10:19
  • Indeed, every feature counts. The problem about "core OOP",- as well as other cores in other systems,- is that what is core changes from person-to-person, from compiler-to-compiler, from hardware-to-hardware. Thus, when you remove some feature, it may be still a core for YOU, but not for ME. – Agnius Vasiliauskas Dec 04 '19 at 10:26
  • @AgniusVasiliauskas: Note that e.g. the working of visibility and lookup in C++ were explicitly designed so that the behavior of the program stays 100% identical if you replace `private:` with `public:`. The only difference is really that `private` enforces a certain amount of desired discipline by having the compiler refuse compilation in some well-defined circumstances. You can do the same thing without being forced. – Damon Dec 04 '19 at 15:33
  • *"However, access modifiers very much matter from a developer's perspective if you're interested in avoiding mistakes."* Due to Murphy's Law, however, there will always be someone desperate enough to bypass access modifiers by using reflection or decompiling the code. – Chaos Monkey Dec 04 '19 at 17:14
  • @Renan It's not an argument. Likewise, you can bypass hands washing, but it doesn't mean that manufacturers should stop producing soap – Agnius Vasiliauskas Dec 04 '19 at 17:21
  • @Damon It's not an argument that `private` or `protected` isn't needed, because you can live without it. So what ? According to your logic `++` isn't needed too, because you can always do `+=1;` instead. Wait ... why stop here ? We don't need a compound plus also, because we can always do `-=-1;`. You may even don't need subtract operation at all too, because you can do it with bit-shifts only. And so on, and so on. It proves nothing about the practical NEED of feature – Agnius Vasiliauskas Dec 04 '19 at 17:38
  • The real usefulness of `protected` is in combination with abstract methods, when you want to force derived class to implement some support method which otherwise _must_ not be accessed externally by object user. So in general _protected_ modifier is something between private & public and is VERY useful. My opinion is that if OOP language doesn't have protected access modifier, then it's not worth working with it at all. – Agnius Vasiliauskas Dec 04 '19 at 17:56
  • @AgniusVasiliauskas You've actually come a long way in proving yourself silly. Because anyone who's sane can see that you don't technically need addition or the nice `+=` operator; and the answer to "does a programming language need addition?" is definitely "No" since you can have a valid and useful programming language without the addition construct (just subtract a negative number if you wanted to add). The addition operator would be nice and useful. But missing it doesn't make it not-a-language. Similarly, access modifiers are nice, but not required for OOP (see: JS, Python). – Delioth Dec 04 '19 at 19:02
  • @Delioth, Yeah, yeah clever boy, why you think I wrote "_We don't need a compound plus also, because we can always do `-=-1;`_" ? Seems you can't read normally opponent posts. Anyway, you miss my main point - we can live with MANY features excluded, so what ? You can build whole house with almost just a hammer, but it doesn't proves that you should reject other useful tools. Similarly, access modifiers is very useful and **should** be implemented in OOP language if possible. – Agnius Vasiliauskas Dec 04 '19 at 19:28
  • @AgniusVasiliauskas Because the question isn't "is `protected` useful to have in OOP?" The question is asking "is `protected` required for OOP?" Yes, most who have used them know that access modifiers are useful at times. In the same way inheritance, pattern matching, and a million other useful features can be useful at times. But the question isn't asking if they're useful. – Delioth Dec 04 '19 at 19:41
  • @AgniusVasiliauskas: There is a massive difference between "access modifiers aren't necessary" and "access modifiers aren't necessary **for OOP**". You keep arguing against the former but no one here has ever claimed that. The topic at hand is about the latter, i.e. whether OOP *inherently depends on* access modifiers. The topic is not whether OOP or access modifiers (by themselves, or combined) should be used by developers. – Flater Dec 05 '19 at 08:36
  • "_Similarly, access modifiers are nice, but not required for OOP (see: JS, Python)_". Thanks god, PHP has all 3 types of access modifiers. – Agnius Vasiliauskas Dec 06 '19 at 08:07
  • @AgniusVasiliauskas Think of it this way: does a car need a windshield to be a car? Well, I'd certainly prefer my car to have a windshield, and I'm not going to enjoy a car without one, **but it would still be a car** even if it didn't have a windshield. Similarly, OOP without access modifiers is not as good, but it's still OOP. – Flater Oct 02 '20 at 22:18
37

No, it's not required: Bjarne Stroustrup, explained how he naively added protected to C++ release 1.2, thinking to provide a useful feature to class developers, just to conclude only 5 years later that it was a nasty source of bugs, that fortunately no one was forced to use. Nowadays, he recommends not to use it.

The practical arguments against protected are the advantages of stronger encapsulation and the principle of the least knowledge:

  • Either a member is public and can be used by anybody;
  • Or the member is private and needs to be protected against external access.
  • A protected member, that requires careful usage (otherwise it would be public) can be misused as much by insiders (developers of derived class) as by anybody else.

Formal arguments confirm the practical experience. This has to do with the Liskov Substitution principle and more precisely its history rule:

We think it ought to be sufficient for a user to only know about the “apparent” type of the object; the subtype ought to preserve any properties that can be proved about the supertype.
- Barbara Liskov & Jeanette Wing in A behavioral notion of subtyping

Without going into the details of the quoted article, the protected members allow a derived class (subtype) to change the state of the base class object (supertype) in an unexpected manner, without relying on its public operations.

This being said, beware of the appearances and false promises. The Swift private is in-between private and protected in other languages:

Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. (...).
- Apple, in The swift programming language

Christophe
  • 74,672
  • 10
  • 115
  • 187
  • 32
    Note that Bjarne advises against using protected _data_ members. He says protected methods can be fine. – BenM Dec 02 '19 at 22:24
  • 1
    @BenM Indded, in the core guidelines Herb and he mention indeed data members. In the book he is much more explicit and general than in the core guidelines. Protected member function, as soon as not const, share some risks with protected data members. – Christophe Dec 02 '19 at 22:33
  • In Swift, extensions are full part of the class. Extensions just allow you to better organise your class. So the fact that only extensions _in the same file_ can access private members makes Swift private more restrictive than C++ private. On the other hand, Swift has “file private” which allows access in the same source file. So you can have a class and five subclasses in the same source file and they all can access file private members. This assumes that you can manage to handle dependencies in the same source file without help by the compiler. – gnasher729 Dec 03 '19 at 11:02
  • @gnasher729 thats’s a valid point, thanks. I didn’t want to make my answer longer to handle this special case. Swift Extensions indeed belong to the class; but anybody could extend it anywhere. There is no equivalent in other mainstream languages. Semantically, it’s as if you could derive a class to add new members but use the name of the old class. Swift’s private therewith elegantly provides protected like access to developers/maintainers of the initial class in the initial file, while enforcing strong privacy from other files and classes. This confirms that protected are not needed ;-) – Christophe Dec 03 '19 at 11:27
  • I disagree with the premise that "protected" undermines the LSP. A much bigger problem is the use of the same interface surface for both public access and subtype overrides. If a public method can't be overridden, but chains to a protected method that can, then the public method can ensure that any operations the protected method are suitably wrapped in whatever way would be needed to uphold the parent's invariants. Such an approach won't work, however, unless the overrides of the protected methods can do things that outside code can't. – supercat Dec 03 '19 at 17:37
  • @supercat Interesting thoughts. Stroustrup agrees with me (or more accurately: I agree with him) about protected undermining the history rule. He explicitly mentions Liskov’s keynote at OOPSLA ( Now history rule is only one very specific, misunderstood and forgotten aspect of LSP; the other aspects of LSP are not necessarily directly undermined. But LSP is like a house of cards: if one aspect fails...) – Christophe Dec 03 '19 at 17:46
  • 2
    @Christophe: No class that allows non-trivial extension can prevent the definition of subclasses that violate the LSP, and languages shouldn't try to prevent subclasses from doing so. Suppose a class is supposed to fire a "changed" event after every complete sequence of updates, and someone wants to extend the class by adding more information as well as a way of changing some old fields and some new ones. I would suggest that the proper design would be to have protected means of changing properties without sending a notify as well as a protected means of sending notification, and require... – supercat Dec 03 '19 at 18:10
  • ...as part of the inheritance contract that any *public* method which changes any properties of the object must send a notification before it returns to its caller. If it's necessary that a notification to be sent after the *last* update, but desirable to avoid sending any other notifications, I see no practical way of accomplishing that without a protected means of performing an update without sending a notication. – supercat Dec 03 '19 at 18:13
  • @Christophe: As a related note, a class may require as part of its constructor that a notification be sent to an object specified as a constructor argument between the time that all subtype initialization is completed and the time the reference becomes available to the code creating the instance. To make this work, there needs to be a distinction between using a base-type constructor to create a base-type object (which should cause the notification to be sent) and using it to create a sub-type object (which defer the notification so the sub-type constructor can send it). – supercat Dec 03 '19 at 18:20
  • @supercat I’m not sure you followed me on the history rule: By forcing derived classes to use public interface of base class, you ensure that the base class behaves as expected regarding its public base behavior. This is the “history rule”. And protected access allows to break this rule and easily create nasty bugs. That’s where practice and theory converge. Now I agree that this is of little help if your basic public behavior includes polymorphic behavior that can be altered. And I agree that removing protected doesn’t solve everything. It’s just that protected should be avoided :-) – Christophe Dec 03 '19 at 18:26
  • 1
    @Christophe: If a class allows non-trivial extensions, it will be possible to create subtypes that violate every imaginable rule, including the history rule. Conversely, if the inheritance contract of a base class requires that all subtypes honor the history rule, then any subtype *which upholds that contract* will honor the history rule. If one wanted to provide a language-based means by which a base class could steer derived classes toward upholding a base-class contract, one could define a category of method which derived classes could override, and which would require... – supercat Dec 03 '19 at 19:03
  • ...that any override either chain to the parent method exactly once and return successfully, raise an exception before the call, or chain to the parent method and then to a specified parent error-handling method and throw an exception, and which would not be invokable by the derived class except as described above. I am unaware of any language where a "private" method could offer such semantics, however. – supercat Dec 03 '19 at 19:06
  • @Christophe: An alternative approach would be to have a sort of "reverse" virtual method for which a class could supply two definitions--one of which would be used for instances of the class, and one of which would be used for instances of sub-types and which would chain to the sub-type method. So if `Animal` defines a subtype `vocalize` method which outputs `Vocalizing (`, then calls `subtype.vocalize`, and then outputs `)'`, and `Cat:Animal` defines a `vocalize` method that outputs "Meow", then calling `vocalize` on a `Cat` would output `Vocalizing(Meow)`. I've never seen any language... – supercat Dec 03 '19 at 19:13
  • ...support such a design, however. – supercat Dec 03 '19 at 19:13
9

Python is also a language that strongly adheres to the object oriented programming approach. It uses the classical approach of classes and objects.

The thing to remember however is that any "word" is just a contract between you and (future) maintainers. Having a different, or even non explicit name for something does not mean that this contract is not there.

Python uses the credo "we're all adults", and expect people to work with the objects instead of against it. Thus it considers everything public and you're expected to make your own contract by describing the class. (PEP8, the design book, notices that prefixing with _ is a good idea to show the contract of private fields IDEs understand this).

Protected (as an idea that you cannot access the variable directly, except if you derive from it) is a weak contract anyways. If you wish to 'prevent' mistakes due to erroneous changes to important fields, to protect the internal state, a protected variable can still change at will, and a derived class can easily expose this and change it badly.

So the question should be on you: "why add an extra paradigm" to a language without direct advantageous uses? YAGNI might also apply here.

paul23
  • 1,061
  • 1
  • 8
  • 14
8

Before we decide that the protected access modifier must be removed from all popular OO languages I would like to point out that it would be pretty inconvenient to lose it.

In abstract base classes that serve as a blueprint for a number of derived classes you will likely have a lot of support methods for these derivatives that will be meaningless to the end user of those derivatives. Ergo, you will get noisy interfaces and you will have to find another way to signal these methods are not supposed to be called by object clients.

Some may say there are ways around that. That you can apply composition instead. They will give you a number of reasons not to use inheritance in the first place. Whatever merit there may be in these statements, protected is there to support the application of inheritance. Writing useful abstract classes without protected is going to be hard.

I can say I don't use it a lot outside abstract base classes. But as long as we have abstract base classes I'd like to keep my protected keyword thank you.

Martin Maat
  • 18,218
  • 3
  • 30
  • 57
3

One of the first object oriented languages, Smalltalk, does not have a protected keyword or mechanism, and private also isn't explicit but implied for instance variables, and suggested by convention for methods. Works pretty well unless people see the malleability as an invitation to hit everything with a big hammer :-)

Hans-Martin Mosner
  • 14,638
  • 1
  • 27
  • 35
1

protected is about access control of data. OOP is about encapsulation.

The main goal of OOP is to structure the code such that entities (data+operations on it) are weakly coupled to each others. The fact that encapsulated data are controlled (relatively to their access) or not is not a necessary concern. Protection is more closely linked to inheritance; one of the technics to realise the generalisation/specialisation relationship. But even inheritance is not necessary, delegation could be used to implement much more subtly the G/S, and in that case protected is of no usage.

1

You mentioned Swift explicitly, so I'll answer about why Swift doesn't have protected.

Unlike many other languages, Swift lets you write "extensions" to other types (classes, structs, enums and protocols alike), even those which you don't own. Such extensions can even allow you to making library A's type conform to library B's protocol (an example of "retroactive modelling"). For example, you might have an Image object (from library A) that you would like to conform to your ORM's protocol DatabaseSerializable (from library B) so that it could be serialized to a database. In most languages, which requires wrapping up everything adapters all over the place. In Swift, you just extend the Image directly to conform to DatabaseSerializable

extension Image: DatabaseSerializable {
    func serailize(to db: Database) {
        // do whatever is necessary to save to the db or whatever
    }

They're a very core feature that heavily influecnes the style of programming done in Swift. For example, they're frequently used to visually separate conformances to multiple protocols, for example:

class Person {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
         self.firstName = firstName
         self.firstName = lastName
    }
}

// This impl can be auto-synthesized by the compiler, but I'm showing it here as an example anyway
extension Person: Equatable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.firstName == rhs.firstName && lhs.lastName == rhs.lastName
    }
}

// This impl can be auto-synthesized by the compiler, but I'm showing it here as an example anyway
extension Person: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(self.firstName)
        hasher.combine(self.lastName)
    }
}

extension Person: CustomStringConvertible {
    var description: String { "\(firstName) \(lastName)" }
}

Now in this example, imagine there was a protected field, socialInsuranceNumber. If I'm in the context of some other class, it shouldn't be accessible. If I'm in the Person class or a subclass, it should be accessible. But what happens if I'm in the context of a Person extension? Should it depend on where the extension is done? (e.g. allow it in the same module as Person, but disallow access from extension in other modules). What happens if I do this?

extension Person {
    public var publicSocialInsuranceNumber: SIN {
        self.socialInsuranceNumber // this should be protected!
    }
}

I've just trivially circumvented the protections a protected access level would offer.

Instead, Swift has fileprivate, which acts like private, except the field is accessible from the defining file. So extension to Person within Person.swift can access socialInsuranceNumber, but Person extensions defined anywhere else can't.

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
Alexander
  • 3,562
  • 1
  • 19
  • 24
0

In Swift, it was decided that a subclass is not significantly related to the base class. If some information is not available to the public, it should not be available to a subclass.

There is also “fileprivate” which allows members to be available within a file only, so if classes are strongly related, they can be implemented in one file.

gnasher729
  • 42,090
  • 4
  • 59
  • 119
  • Swift has lots of inconsistency on this one. Finally they have something fixed going forward, else migration from Swift 3 days was painful and confusing. – Bishal Ghimire Dec 04 '19 at 07:16
0

As Flater wrote, acces restrictions are not strictly needed.

And some argue that protected access is trying to do multiple things at once. You can use protected in case like:

  1. Method should be called by subclass methods
  2. Method should be implemented by subclass methods and will be called by superclass or other subclasses
  3. Method that can be ovveriden by subclass and will be called by superclass or other subclasses
  4. similar things with Fields

better modifiers (in java ish syntax):

  1. protected final
  2. split into two method, one protected (or private, if subclasses are not supposed to call it) final (that calls) and another protected abstract that subclasses should implement, but not call.
  3. same as 2. but without abstract

And to make it shorter and clearer, use 3 different words.

user470365
  • 1,229
  • 6
  • 8