[swift-evolution] [Proposal] Protected Access Level

Vanderlei Martinelli vmartinelli at alecrim.com
Sat May 28 17:52:55 CDT 2016


Hello.


This is the first draft. I'd like to know your opinion about it.

(I know that this subject could have been discussed before. If so, please
indicate me the correct thread to follow and interact.)


Regards,

Vanderlei Martinelli


---


Introduction

Protected access level will enable entities to be used within the container
type and by derived types only.
Motivation

Today Swift has three access levels (public, internal and private), but
lacks a way to describe a member that can be only visible to its type or
derived types.

A common case is the UIView from UIKit. Many developers are tempted to make
this call:

view.layoutSubviews()

The documentation says: "You should not call this method directly. If you
want to force a layout update, call the setNeedsLayoutmethod instead to do
so prior to the next drawing update. If you want to update the layout of
your views immediately, call the layoutIfNeeded method."

But yes, you should call this method directly if you are subclassing the
view and needs to perform additional layout to its subviews ("subclasses
can override this method as needed"):

public override func layoutSubviews() {
    // We are calling the super method directly here.
    super.layoutSubviews()

    // Do more adjustments to this view's subviews...}

So, yes, we can call this method directly when subclassing, but the Swift
compiler will not prevent you from do this when not subclassing or from any
other foreign class. It will not even issue a warning.

In Objective-C problems like this are usually "solved" my adding a kind of
"protected" header (.h) that is intended to be included only when the
developer is subclassing. In Swift we do not have headers, but we have the
new access level model. So, if the declaration of this method was...

protected func layoutSubviews()

... no one outside the class or derived classes would be allowed to call
this method directly.

Of course, there are other cases in the Cocoa frameworks and there are many
other cases when we are developing software in Swift that the protected access
level would be very usefull.
Proposed solution

Create the protected access level.
Detailed designReference Types (classes)

When declarated by a class the protected member will be visible to the
class itself and all the derived classes.

// BaseClass.swiftpublic class BaseClass {
    public protected(set) var x = 20
    protected let y = 10

    protected func doSomething() {
        // ...
    }}
// DerivedClass.swiftpublic class DerivedClass: BaseClass {
    protected override doSomething() {
        self.x = 10 * self.y
    }}

If the member is declared as final then it will be visible but not can be
overrided by the derived classes. Just like it works with other access
levels.
Value Types (structs, enums, etc.)

Value types cannot have derived types. In this case the protected access
level does not make sense and will not be allowed in their members.
Protocols

Protocols do not declare access level for their members. So the
protected access
level is not applicable here.
Extensions

Extensions will not be able do be protected nor their members.
Special Note

The protected access level can only be applied to classes, structs and
other types when nested inside other type. So the following code will not
compile:

// ERROR: A first level class cannot be protected.
protected class MyProtectedClass {
    /// ...}

But nested declarations will be allowed, so this code will compile:

// We can declare a protected class (or struct, enum, etc.) if// and
only if they are nested inside other type.public class MyPublicClass {
    protected class MyProtectedClass {
        /// ...
    }}
// Since `MyProtectedClass` is nested and protected we// can have
access to it here.public class MyDerivedClass: MyPublicClass {
    public func doSomething() {
        let c = MyProtectedClass()

        /// ...
    }}

Impact on existing code

The imported Cocoa frameworks may have annotations on the "Objective-C
side" that will inform if one member is protected. If this will be case
(for the layoutSubviews method, as example), only code accessing these now
protected members outside the owner class and its derived classes will have
to change (currently this can be considered an error, anyway).

Any other code will be not impacted by this feature as it is new to the
language.
Alternatives considered

Do not add the protected access level to the current model.


---
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160528/10afdc4f/attachment.html>


More information about the swift-evolution mailing list