Protected access level / multiple class/struct/protocol APIs


(Thorsten Seitz) #1

The problem with protected is that it provides virtually no protection at all; you can trivially expose it in a derived class

Extensions further dilute the enforceability of “protected”, since anyone would be able to use an extension to dump methods into a class’s namespace and access its supposedly-protected bits.

I don’t understand the need to protect against exposing something deliberately. We don’t have a goal of restricting other developers, we’re only saving them from accidental mistakes.

Totally agree, access control is not intended to be protection against hacking. If a derived class wants to expose something then that is absolutely fine as long as it makes sense for the derived class.

If a method was marked private in the base class, then it is very likely that the name of the method, the design of its argument list and its return value did not go through the same detailed design review as if the method would have been meant to be part of the class’ interface from the start. So it’s rather unlikely that increasing the visibility in an override is good idea and in the spirit of the original writer of the private method.

The design review and whether something is a good idea is left as a responsibility for those subclasses that choose to expose methods. The intentions of the original class author don’t override the intentions of the subclass author.

Exactly.

-Thorsten

···

Am 31. März 2016 um 05:15 schrieb Andrey Tarantsov via swift-evolution swift-evolution@swift.org:


(Joe Groff) #2

The problem with protected is that it provides virtually no protection at all; you can trivially expose it in a derived class

+

Extensions further dilute the enforceability of "protected", since anyone would be able to use an extension to dump methods into a class's namespace and access its supposedly-protected bits.

I don't understand the need to protect against exposing something deliberately. We don't have a goal of restricting other developers, we're only saving them from accidental mistakes.

Totally agree, access control is not intended to be protection against hacking. If a derived class wants to expose something then that is absolutely fine as long as it makes sense for the derived class.

My point is that "protected" *isn't* access control. If we added it, it would have to be as an independent modifier. Private/internal/public fundamentally affect semantics—private and internal code is only accessible within a module, so we have full knowledge of their use sites at compile time and can be more permissive with extensions, implicit constructors, and other features. Public API can be used by arbitrary unknown external code so requires additional restrictions to ensure that the interface remains stable. "Only usable by subclasses" is an orthogonal axis to this—if a method is only usable by external subclasses, it requires all of the same restrictions as public code. If a method is only usable by subclasses within the module, it can behave like a private or internal method.

-Joe

···

On Mar 30, 2016, at 11:31 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:
Am 31. März 2016 um 05:15 schrieb Andrey Tarantsov via swift-evolution <swift-evolution@swift.org>:

If a method was marked private in the base class, then it is very likely that the name of the method, the design of its argument list and its return value did not go through the same detailed design review as if the method would have been meant to be part of the class’ interface from the start. So it’s rather unlikely that increasing the visibility in an override is good idea and in the spirit of the original writer of the private method.

The design review and whether something is a good idea is left as a responsibility for those subclasses that choose to expose methods. The intentions of the original class author don't override the intentions of the subclass author.

Exactly.

-Thorsten


Access control below public [not `protected`]
(Thorsten Seitz) #3

The problem with protected is that it provides virtually no protection at all; you can trivially expose it in a derived class

+

Extensions further dilute the enforceability of "protected", since anyone would be able to use an extension to dump methods into a class's namespace and access its supposedly-protected bits.

I don't understand the need to protect against exposing something deliberately. We don't have a goal of restricting other developers, we're only saving them from accidental mistakes.

Totally agree, access control is not intended to be protection against hacking. If a derived class wants to expose something then that is absolutely fine as long as it makes sense for the derived class.

My point is that "protected" *isn't* access control. If we added it, it would have to be as an independent modifier. Private/internal/public fundamentally affect semantics—private and internal code is only accessible within a module, so we have full knowledge of their use sites at compile time and can be more permissive with extensions, implicit constructors, and other features. Public API can be used by arbitrary unknown external code so requires additional restrictions to ensure that the interface remains stable. "Only usable by subclasses" is an orthogonal axis to this—if a method is only usable by external subclasses, it requires all of the same restrictions as public code. If a method is only usable by subclasses within the module, it can behave like a private or internal method.

Ah, now I understand what you mean! Thanks for clarifying!
I agree that this has to be taken into account when defining what „protected“ means and how it interacts with other parts of the language.

-Thorsten

···

Am 31.03.2016 um 17:51 schrieb Joe Groff <jgroff@apple.com>:

On Mar 30, 2016, at 11:31 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:
Am 31. März 2016 um 05:15 schrieb Andrey Tarantsov via swift-evolution <swift-evolution@swift.org>:

-Joe

If a method was marked private in the base class, then it is very likely that the name of the method, the design of its argument list and its return value did not go through the same detailed design review as if the method would have been meant to be part of the class’ interface from the start. So it’s rather unlikely that increasing the visibility in an override is good idea and in the spirit of the original writer of the private method.

The design review and whether something is a good idea is left as a responsibility for those subclasses that choose to expose methods. The intentions of the original class author don't override the intentions of the subclass author.

Exactly.

-Thorsten


(Andrey Tarantsov) #4

My point is that "protected" *isn't* access control. If we added it, it would have to be as an independent modifier. Private/internal/public fundamentally affect semantics—private and internal code is only accessible within a module, so we have full knowledge of their use sites at compile time and can be more permissive with extensions, implicit constructors, and other features. Public API can be used by arbitrary unknown external code so requires additional restrictions to ensure that the interface remains stable. "Only usable by subclasses" is an orthogonal axis to this—if a method is only usable by external subclasses, it requires all of the same restrictions as public code. If a method is only usable by subclasses within the module, it can behave like a private or internal method.

Okay. So you see it as “public subclassonly”, leaving space for “internal subclassonly” (which makes sense, although not as important in practice).

I can agree with that, let's consider it a new strawman.

I wonder, though, if you guys have additional, fresh ideas on the underlying problem. We're not really limiting to subclasses here — we're limiting to “extenders” aka “service providers”, and those don't necessarily take a form of a subclass. I've listed some examples in my strawman: an implementation of a protocol, an extension of a class/protocol.

Are there any novel and fresh ideas that would take care of all that in a straightforward and uncomplicated way?

A.


(Andrey Tarantsov) #5

Let me bump this thread. How do we move forward?

Here's an interface of another Swift class I've just made (slowly rewriting my Obj-C components to Swift here):

public class SoloContainerViewController: UIViewController {

    private var _contentViewController: UIViewController?

    public var contentViewController: UIViewController? // delegates to setContentViewController:animated:completion:

    public init(contentViewController: UIViewController?) { ... }

    public required init?(coder aDecoder: NSCoder) { ... }

    public override func viewDidLoad() { ... }

    public func setContentViewController(contentViewController: UIViewController?, animated: Bool, completion completionBlock: dispatch_block_t?) { ... }

    public /*protected*/ func transition(fromView oldView: UIView?, toView newView: UIView?, animated: Bool, completion completionBlock: (finished: Bool) -> Void) { ... }

    public /*protected*/ func willTransitionToContentViewController(newViewController: UIViewController?) { ... }

    public /*protected*/ func didTransitionFromContentViewController(oldViewController: UIViewController?) { ... }

}

This is madness, we have to do SOMETHING!

This class is designed to be subclassed, with a bunch of hooks that subclasses may be interested in. Most of the reusable views and view controllers that I make look like this.

Even when I use delegates, I still forward delegate calls through overridable protected methods, based on my long history of subclassing UIScrollView (and other controls) and wishing that the subclass had access to the delegate methods.

Nobody outside of the class should be interested in those protected methods; they are not safe to call, they're override points.

And I often have to pick very telling method names, so that I don't end up accidentally calling one of those methods from outside. Sometimes that's fairly hard, like when there's a public save(), a private saveNow() and a protected saveContent().

Our best consensus the last time was:

My point is that "protected" *isn't* access control. If we added it, it would have to be as an independent modifier.

Okay. So you see it as “public subclassonly”, leaving space for “internal subclassonly” (which makes sense, although not as important in practice).

I can agree with that, let's consider it a new strawman.

So how do we move forward?

A.