27

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?

  • 22
    No, protected is not required. You said it yourself: it is a "convenience." – Robert Harvey Dec 2 at 1:52
  • 56
    OOP doesn't need private/public either. Many OOP languages works perfectly fine without public/private access modifiers. – Lie Ryan Dec 2 at 10:36
  • 4
    @LieRyan, original OOP languages were designed with all data being private and all methods being public. – user28434 Dec 2 at 15:00
  • 8
    Access control* modifiers are not needed for OOP at all, they solve a different, yet related, set of problems. – Polygnome Dec 2 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 3 at 11:54
45

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".

  • 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 2 at 19:31
  • @Delioth Good point. Updated my answer to include your comment. – Flater Dec 3 at 7: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 3 at 8: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 3 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 3 at 19:39
32

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

  • 31
    Note that Bjarne advises against using protected data members. He says protected methods can be fine. – BenM Dec 2 at 22:24
  • @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 2 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 3 at 11:02
  • 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 3 at 18:10
  • 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 3 at 19:03
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.

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.

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 :-)

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
    Your first two sentences are splitting a mighty fine hair... – Jared Smith Dec 2 at 21:33
  • 1
    @JaredSmith Why? A lot of no OOP languages tried to protected data (static vs extern, etc). Every language that support modularity tackles the problem in some way. – Jean-Baptiste Yunès Dec 3 at 5:14
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.

  • 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 4 at 7: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.

0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.