[Proposal] Protected Access Level

I agree that we should be looking for what makes sense, not just what we’ve seen in other languages. That said, there seems a lot of hate for OOP in general that seems to be clouding people’s vision here.

I think that “protected” as a form of access control is exactly what we want: rights that subclasses should be allowed, but other classes should not. Generally they refer to internal state that only the class itself, or its subclass, has any business either updating or calling.

Lets drop the word “protected” for a second and actually examine the use cases for differing access control in classes. I think the best example of this in different contexts are:

1. Methods and properties that only subclasses must access, but other code has no business updating. An example of this UIGestureRecognizer. State machine type access is something where external items should not access, but internal state may require the rights to update.

2. Methods and properties that should be overridable, but are helper methods and shouldn’t be called by external methods, and perhaps shouldn’t be even called directly. This includes -layoutSubviews on UIView, a multitude of other methods in UIKit, etc. Thus I think Brent had a good point that calling a method might need to have different access rights to overriding it.

I think #1 shows specifically the need for access control for subclasses only, and thus a ‘protected’- style access control level.
I think #2 shows a need to differentiate the access rights of calling a method from access rights to see or override the method.

While we can find workarounds that obfuscate access, these aren’t access controls, they’re convoluted workarounds to avoid correcting our access control rules in the first place.

How do these things bridge into Objective-C?
Protected doesn’t make sense in Objective-C. You cannot subclass a Swift Class in Objective C, so overriding is irrelevant. I suspect the rule should be simple: Anything Protected should not be visible to Objective-C, much like private is hidden currently.

- Rod

···

On 30 May 2016, at 8:45 AM, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

Vanderlei, my point in bringing such topics to this discussion is to make everyone here think if we're trying to really enhance the language within its intended purpose or if we're trying to change the language into something else were familiar with from other languages we work/ed with just because we're used to work like that. I just started thinking about this today and just cannot stop now. No intention to start a war here but I think everyone should ask themselves this for every proposed change to the language.

About the topic at-hand, we have to remember Swift is bridged to Objective-C, which has no protected (or abstract). How do you propose these protected members be bridged should the proposal pass?
From: Vanderlei Martinelli via swift-evolution <mailto:swift-evolution@swift.org>
Sent: ‎29/‎05/‎2016 06:56 PM
To: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Protected Access Level

Thank you all for your comments. :-)

Well... My goal is to keep the thing really simple and do not start a new "OOP x POP" (or "something" x "other thing") war.

"Protected" access level is not a new concept at all (except for the Swift language), so I did not propose anything preposterous.

Of course in the Swift of my dreams we also have "abstract" access level modifier, "protected" access level, *real* "private" access level and "file" access level modifier (along with many, many other things, of course). But this proposal is not about this. It is only about include the "protected" access level.

There is, however, something that I need to get off my chest: I really would like to have the freedom to go to the depths with protocols as well with classes. I work in real apps everyday that uses Cocoa frameworks (based on classes) and these apps must be shipped and I like them well written. Maybe am I insane for proposing a better support for classes in Swift? If so, this explains why every time I suggest better support for classes in Swift there is an endless discussion and someone proclaims the death of OOP and is it. OK... Maybe someday we will not have more classes in Swift. Until there: the current language status is the best way to handle OOP in Swift? Or is there a better way? I think there is.

Regards,

Vanderlei Martinelli

On Sat, May 28, 2016 at 7:52 PM, Vanderlei Martinelli <vmartinelli@alecrim.com <mailto:vmartinelli@alecrim.com>> wrote:
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 design
Reference Types (classes)

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

// BaseClass.swift
public class BaseClass {
    public protected(set) var x = 20
    protected let y = 10
    
    protected func doSomething() {
        // ...
    }
}

// DerivedClass.swift
public 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�

[The entire original message is not included.]
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

1 Like

Couldn’t you use the same reasoning to claim there shouldn’t be access control at all? Just add documention on methods you want to mark private telling users of the library not to call them!

I guess you are making fun, but actually, good old Objective-C messaging works just that way:
You can call all those dangerous and forbidden private methods easily...
Writing special comments is just one way to document APIs; having no (official) documentation at all is documentation as well ("don't use this!").

Most technical limitations can be cracked by skilled hackers (working around "protected" is especially easy), so I really think that (for example) declaring a method "final" says "I don't want this to be changed in a subclass" in the first place, and the compiler error that is triggered when you try to break the limitation is little more but a remainder.

Enforcing limitations using hacks causes confusion, so I would never use such tricks in production code.

You know the default access is was is used for this, right? And in this case I don't think they meant it for external subclasses to be able to access this change.

I think this is how Swift was meant to work allowing only classes in a certain module to access such "private shared" parts and using delegates for these extensions. I'm not saying I'm against protecteds but it's hard to get used to use another way of programming when most other languages we previously learned had a different philosophy.

Sure everyone has the right to discuss they like this new philosophy or not but we should also question ourselves if this is the right way to go because it will completely change the philosophy of the language. Should this pass, we may start facing the core library using the delegate philosophy (I don't believe Apple will change it) and third-party modern frameworks using old school subclassing with protected parts. That's two ways of doing the same thing and I don't think this will be much good to anyone.

···

-----Original Message-----
From: "Charlie Monroe via swift-evolution" <swift-evolution@swift.org>
Sent: ‎29/‎05/‎2016 08:29 AM
To: "Brent Royal-Gordon" <brent@architechies.com>
Cc: "swift-evolution" <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Protected Access Level

My answer is this: There is nothing magical about being a subclass that ought to grant access to those methods.

There is - it's a family member that you let use your summer house. Without the metaphor, here is an example for this being useful:

URLConnection subclass may want to update the URL in case of a redirect, but you don't really want to expose the setter for the URL to public.

For instance, if your subclass grows very complicated and you extract a helper object, it's perfectly reasonable for that helper object to want to access the "subclass-only" API.

That's what "friend" classes are for in C++, similar concept would be applied here.

Contrarily, simple subclasses might not need that API, and exposing it to them would be an unnecessary risk. And there are things which you don't subclass at all which could benefit from being hidden away—think of the Objective-C runtime, which has some parts which every app needs (like the definition of `BOOL`) and othe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

attempting to write a Swift compiler in Swift today would probably result in hard to read/reason about source code.

Hmm, I still have to find some time to start working in this...

I agree - both will need to be addressed in the future to make the language complete. There are some valid points, however, in the blog post - would you allow extensions to access protected variables and potentially expose them to other classes? I.e:

/// Class in module A:
class View {
  protected func layoutSubviews()
}

/// In module B:
extension View {
  func doLayoutSubviews() {
    self.layoutSubviews()
  }
}

Or would you disallow access from extensions to prevent this kind of abuse?

···

On May 29, 2016, at 11:19 AM, Goffredo Marocchi <panajev@gmail.com> wrote:

Without wither abstract classes or a protected access modifier, the status quo, that kind of ExceptionThisMethodShouldBeOverridden are really ugly bad code there is no alternative to beyond a religious stop using classes and sub classing... did you not know about your pop saviour ;)?

Sent from my iPhone

On 29 May 2016, at 08:38, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

Ditto - I would love to be able to disallow non-subclasses accessing/modifying some variables.

Though, I'm not sure what would be the stand on this from the core team - according to Apple's blog they've already considered protected access level:

Access Control and protected - Swift Blog - Apple Developer

Charlie

On May 29, 2016, at 7:56 AM, Riley Testut via swift-evolution <swift-evolution@swift.org> wrote:

Unless I'm missing something Brent, your suggestions still wouldn't allow the developer to provide a public class in a module designed to be subclassed by clients in another module and access these "private" details, which is a real problem I'm having in my current project.

I have a framework which provides an abstract model object designed to be subclassed (and yes it has to be a class and not a struct for a multitude of reasons :stuck_out_tongue:) by clients of the framework. There are several convenience methods + properties I have exposed for subclasses to use, but they should really be implementation details; a client using these model objects should not have to know about them. Even worse, several of the properties are mutable so the subclasses can modify them, but they certainly should *not* be modified by anything else.

Right now, I'm limited to simply commenting something akin to "DO NOT CALL" next to these methods/properties, which definitely goes against Swift's safety focus. For these reasons, I'm 100% in support of a protected access control modifier.

On May 28, 2016, at 8:11 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

To begin with, I'm not a fan of `protected` access. But even leaving that aside, I have a few questions and critiques.

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

This example is illuminating in several ways.

* The rule is not simply that "only the class should call `layoutSubviews()`"; it is effectively "*you* should never call `layoutSubviews()` except when `super`ing up from your override". Calling `layoutSubviews()` from `insertRows(at:)` is just as much a mistake if `insertRows(at:)` is part of the class as if it is not. So isn't `protected` insufficiently strict to properly serve this use case?

* At the same time, something outside `layoutSubviews()` has to be able to call `layoutSubviews()`. In the case of UIKit, though, that "something" is always within UIKit itself, never outside it. So should `protected` have a "bottom", a level below which calls are unrestricted? For instance, in UIKit's case you might have `protected fileprivate`, meaning "anything up to `fileprivate` has unrestricted use; anything above that can override and `super` up from its override, but not use it any other way".

protected fileprivate func layoutSubviews()

* `layoutSubviews()` is also something you should probably always `super` up to. Have you considered addressing `super` requirements at all?

In short, is a traditional `protected` really the feature you want to handle this use case, or would a very different design actually suit it a lot better?

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

In what scope? The same as the class?

Is there not room for, for instance, "usable without restriction in this file, override-only in the rest of this module, invisible outside it"? For instance, `internal(protected) fileprivate`, or perhaps `internal(override) fileprivate`? `layoutSubviews()` might then be `public(override) fileprivate`—the ability to override is public, the ability to use it unrestricted is filewide.

public(override) fileprivate func layoutSubviews()
internal(override) fileprivate func privateSubclassingHook()

public protected(set) var x = 20

Of course, that might be difficult to combine with the `(set)` syntax. `public(set: override)`, maybe? With, for instance, `public internal(set: override) private(set)` if you want the property's getter public and its setter overridable internally and callable in private scope.

public(override) fileprivate func layoutSubviews()
internal(override) fileprivate func privateSubclassingHook()
public(get, set: override) internal(set) var x = 20

But there's something about this that's starting to seem a little rotten. I think the problem is that we're not really trying to widen the ability to override, we're trying to restrict the ability to call. Let's try restructuring along those lines:

public fileprivate(call) func layoutSubviews()
internal fileprivate(call) func privateSubclassingHook()
public internal(set: call) var x = 20

That seems much cleaner to me.

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.

With the "overridable but otherwise unusable" conception I'm suggesting, this would not be the case, of course.

Protocols

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

But `protected` is quite different from other access levels; it does not limit the visibility of the symbols, but rather their use. And protocols face the same sort of problem as classes, where certain members are essentially override hooks and shouldn't be called directly outside a particular scope.

So I think we ought to allow `accesslevel(call)`, but not a plain `accesslevel`:

public fileprivate(call) func layoutSubviews()
internal fileprivate(call) func privateSubclassingHook()
public internal(set: call) var x = 20
internal(call) func protocolConformanceHook()
fileprivate(set: call) var onlyProtocolSetsThis: Int { get set }

Extensions

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

This is very vague. There are several things extensions might try to do with protected members:

* Declare new ones
* Override existing ones
* Call existing ones

Which of these, if any, are permitted? Why?

In my conception, I would permit extensions to behave as the type they extended did. Extensions could declare new members with restricted calling and override existing ones. They would not be able to call, except when supering from an override, unless they were within scope of the `call` access control. In other words, they'd behave just like any other code at that location. That's how we want extensions to work.

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 {

What does it mean to "use" a protected class, though? Clearly you can call its methods, if only through AnyObject or a non-protected superclass or a protocol it conforms to. Does it mean you can't instantiate it? Does it mean you can't subclass it? Does it mean you can't call methods that aren't on its supertypes? All of the above? None?

One more thing that didn't come up: Testability. I believe that importing a module with `@testable` should disable its call restrictions, even ones inherited from outside that module. Thus, even if *you* cannot call your `layoutSubviews()`, your test suite can.

So, in short, my counter-proposal is:

public fileprivate(call) func layoutSubviews()
internal fileprivate(call) func privateSubclassingHook()
public internal(set: call) var x = 20
internal(call) func protocolConformanceHook()
fileprivate(set: call) var onlyProtocolSetsThis: Int { get set }

In other words:

* There is a new aspect of the member, `call`, which controls the ability to actually call the member, as opposed to overriding it. No `call`, no calling (except when `super`ing up from an override).

* `call` is used in combination with one of the existing access modifiers: `public(call)` `internal(call)` `fileprivate(call)` `private(call)`. `call`'s visibility is always less or equal to the member itself.

* To control the callability of a setter independently from both the getter and the overridability of the setter, use `set: call`.

* Extensions behave just like type definitions at the same location with regards to `call`.

* Protocols can use access modifiers with `call` to prevent unauthorized code from calling a member. The access control level to implement a member continues to be as wide as the access control level of the protocol itself.

* `@testable` disables `call` restrictions on the types it imports, so the test suite can call any visible member, even ones inherited from other modules.

* There should probably also be some sort of "super required" warning/error, but this is an orthogonal feature and can be left for a separate proposal.

I think that feature will be closer to the one you actually *want*, as opposed to the one that other languages have cargo-culted from SIMULA-67.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Multiple ways for multiple needs. The same way you can support both delegation as well as blocks based callbacks.

···

Sent from my iPhone

On 29 May 2016, at 13:23, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

You know the default access is was is used for this, right? And in this case I don't think they meant it for external subclasses to be able to access this change.

I think this is how Swift was meant to work allowing only classes in a certain module to access such "private shared" parts and using delegates for these extensions. I'm not saying I'm against protecteds but it's hard to get used to use another way of programming when most other languages we previously learned had a different philosophy.

Sure everyone has the right to discuss they like this new philosophy or not but we should also question ourselves if this is the right way to go because it will completely change the philosophy of the language. Should this pass, we may start facing the core library using the delegate philosophy (I don't believe Apple will change it) and third-party modern frameworks using old school subclassing with protected parts. That's two ways of doing the same thing and I don't think this will be much good to anyone.
From: Charlie Monroe via swift-evolution
Sent: ‎29/‎05/‎2016 08:29 AM
To: Brent Royal-Gordon
Cc: swift-evolution
Subject: Re: [swift-evolution] [Proposal] Protected Access Level

> My answer is this: There is nothing magical about being a subclass that ought to grant access to those methods.

There is - it's a family member that you let use your summer house. Without the metaphor, here is an example for this being useful:

URLConnection subclass may want to update the URL in case of a redirect, but you don't really want to expose the setter for the URL to public.

> For instance, if your subclass grows very complicated and you extract a helper object, it's perfectly reasonable for that helper object to want to access the "subclass-only" API.

That's what "friend" classes are for in C++, similar concept would be applied here.

> Contrarily, simple subclasses might not need that API, and exposing it to them would be an unnecessary risk. And there are things which you don't subclass at all which could benefit from being hidden away—think of the Objective-C runtime, which has some parts which every app needs (like the definition of `BOOL`) and othe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

You seem to be producing a convoluted solution to create a “sharps drawer” but Swift is supposed to be safe. You shouldn’t access the sharps drawer there and there are better ways for us to stop you than to simply “trust” the developer - it’s to do the right thing, and provide a protection level that stops the access where it’s not needed: “protected”.

The thing is, though, the contents of the sharps drawer are *still* sharp even if you're old enough to use a knife. And similarly, APIs like the `state` setter are *still* dangerous even if you've subclassed `UIGestureRecognizer`. To be sure, it is more likely that you'll *need* to set `state`, but it's still not something you should do carelessly or without understanding the consequences.

`protected` fails to acknowledge this. It conflates the act of inheriting interface and implementation with the act of gaining access to dangerous operations. It would be like a drawer which automatically mixed the knives in with the other utensils when an adult opened it.

This is a general problem with traditional OO: Inheritance bundles a whole bunch of separate semantics into a single operation. Obviously some of these are so ingrained in OO that they can't be separated; you're not going to separate inheritance of interface from inheritance of implementation. But the sharps drawer does not *have* to be part of the bundle, and there are compelling reasons to look for a different solution—one which fits this use case better, *and* simultaneously serves other use cases like non-subclassed types.

To give you an idea, here are a couple more potential "sharps drawers" in UIKit which `protected` would not serve well:

* View controller containment. There are very few view controllers which actually contain other view controllers; for most, these calls are a great way to mess things up. And yet some of these members, like `childViewControllers`, are definitely things you need to be able to access from outside a view controller, for instance to find a view controller to present an error message on. `protected` would expose these methods to vast amounts of code that doesn't need them, while hiding them from code that does.

* UIKeyInput and UITextInput methods should only be used by custom keyboards (either `inputView`s or keyboard extensions), but they're exposed to everybody, sitting right alongside methods intended for wide use. The intended clients for these APIs have no inheritance relationship whatsoever with the classes they would need to call them on, so `protected` would be of absolutely no help here.

···

--
Brent Royal-Gordon
Architechies

1. Methods and properties that only subclasses must access, but other code has no business updating. An example of this UIGestureRecognizer. State machine type access is something where external items should not access, but internal state may require the rights to update.

But again, "external" does not necessarily mean "non-subclass", and "internal" does not necessarily mean "subclass". A particular subclass might not require access, and a helper type/function might require access.

This insight—that the type graph doesn't always reflect the boundaries of concerns—is the very basis of Swift's current access control design. It's the reason why `private` (soon to become `fileprivate`) doesn't grant visibility to extensions on the same type in different files, but *does* grant it to extensions on different types in the same file. This is an important innovation in Swift's access control design, and we shouldn't ignore it when we're thinking about `protected`.

···

--
Brent Royal-Gordon
Architechies

The rust compiler is written in rust… many compilers are bootstrapped and then written in their own language. Looking at the swift language vs C++ features used in the current compiler, I wager it would be a suicide mission to try with Swift 3.0.

···

On May 29, 2016, at 2:27 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:

attempting to write a Swift compiler in Swift today would probably result in hard to read/reason about source code.

Hmm, I still have to find some time to start working in this...

I missed the last part when you are talking about bridging TO Objective-C,
but Rod Brown answered that very well (thanks).

-Van

···

On Sun, May 29, 2016 at 8:50 PM, Vanderlei Martinelli < vmartinelli@alecrim.com> wrote:

Hi Leonardo.

Thank you for your answer.

I understand your point of view and I agree that it is better to look
forward. But today we still have to deal with decades of legacy Cocoa code
written using classes. If tomorrow a new set of Cocoa frameworks written in
Swift using protocols appears, maybe we can forget all of this discussion.
But OOP is very important and don't think it is the "past". I see future in
"POP" as I see in "OOP" and I think we can have OOP and POP living in
harmony in Swift. And since we have support to classes in Swift, I think it
shall have a full featured support for classes.

Perhaps my reaction in the last message sounds like I am overreacting when
seen in the context of this thread. But I am programming in Swift since the
first day it was publicly available (and I think that the first almost
usable version to create real world apps was the 1.2). Since the old
forums, when Swift was not yet open source, I have been insisting on
certain improvements.

About bridging member declarations from Objective-C, many of these classes
already have separated headers with the members intended to be overrided.
Exceptions to this rule could be "annotated" somehow. (I would like to
mention classes that are entirely intended to be subclassed and not used as
is in Cocoa frameworks, but this is about "abstract" access level modifier
and not part of this proposal.)

Regards,

Vanderlei Martinelli

On Sun, May 29, 2016 at 7:45 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:

Vanderlei, my point in bringing such topics to this discussion is to make
everyone here think if we're trying to really enhance the language within
its intended purpose or if we're trying to change the language into
something else were familiar with from other languages we work/ed with just
because we're used to work like that. I just started thinking about this
today and just cannot stop now. No intention to start a war here but I
think everyone should ask themselves this for every proposed change to the
language.

About the topic at-hand, we have to remember Swift is bridged to
Objective-C, which has no protected (or abstract). How do you propose these
protected members be bridged should the proposal pass?
------------------------------
From: Vanderlei Martinelli via swift-evolution
<swift-evolution@swift.org>
Sent: ‎29/‎05/‎2016 06:56 PM
To: swift-evolution <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Protected Access Level

Thank you all for your comments. :-)

Well... My goal is to keep the thing really simple and do not start a new
"OOP x POP" (or "something" x "other thing") war.

"Protected" access level is not a new concept at all (except for the
Swift language), so I did not propose anything preposterous.

Of course in the Swift of my dreams we also have "abstract" access level
modifier, "protected" access level, *real* "private" access level and
"file" access level modifier (along with many, many other things, of
course). But this proposal is not about this. It is only about include the
"protected" access level.

There is, however, something that I need to get off my chest: I really
would like to have the freedom to go to the depths with protocols as well
with classes. I work in real apps everyday that uses Cocoa frameworks
(based on classes) and these apps must be shipped and I like them well
written. Maybe am I insane for proposing a better support for classes in
Swift? If so, this explains why every time I suggest better support for
classes in Swift there is an endless discussion and someone proclaims the
death of OOP and is it. OK... Maybe someday we will not have more classes
in Swift. Until there: the current language status is the best way to
handle OOP in Swift? Or is there a better way? I think there is.

Regards,

Vanderlei Martinelli

On Sat, May 28, 2016 at 7:52 PM, Vanderlei Martinelli < >> vmartinelli@alecrim.com> wrote:

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�

[The entire original message is not included.]

But `protected` is quite different from other access levels; it does not limit the visibility of the symbols, but rather their use. And protocols face the same sort of problem as classes, where certain members are essentially override hooks and shouldn't be called directly outside a particular scope.

So I think we ought to allow `accesslevel(call)`, but not a plain `accesslevel`:

  public fileprivate(call) func layoutSubviews()
  internal fileprivate(call) func privateSubclassingHook()
  public internal(set: call) var x = 20
  internal(call) func protocolConformanceHook()
  fileprivate(set: call) var onlyProtocolSetsThis: Int { get set }

Given that this is almost identical to the pitch I floated to the list some months ago, all the way down to the fileprivate(call) syntax (well, back then “fileprivate” was “private”, so it was private(call)), I’m +1 on this.

···

On May 28, 2016, at 8:11 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

On May 29, 2016, at 6:55 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

The thing is, though, the contents of the sharps drawer are *still* sharp even if you're old enough to use a knife. And similarly, APIs like the `state` setter are *still* dangerous even if you've subclassed `UIGestureRecognizer`. To be sure, it is more likely that you'll *need* to set `state`, but it's still not something you should do carelessly or without understanding the consequences.

This, though, reads like “The 17-year-old might cut himself with a knife, even though he *needs* the knives to help with the cooking. So, let’s give knives to the newborn!”

Charles

Brent,

You make a very good point about the fact internal is not necessarily the same as subclass, something I hadn’t considered.

I think that the level of exposure these APIs then get - ultimately Public within frameworks - is too unrestricted. At least in Objective-C, we can vet the headers to break classes into separate sections where we don’t disclose certain headers to show something by default. Can we think of a way to allow opt-in access?

This ultimately gets into one of my major sore points with Swift: Framework Generated Headers suck. The Framework story for Swift seems shockingly ill conceived at this time. I could never imagine Apple shipping a framework with the current Framework setup… but I’m going into the weeds...

-Rod

···

On 30 May 2016, at 10:03 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

1. Methods and properties that only subclasses must access, but other code has no business updating. An example of this UIGestureRecognizer. State machine type access is something where external items should not access, but internal state may require the rights to update.

But again, "external" does not necessarily mean "non-subclass", and "internal" does not necessarily mean "subclass". A particular subclass might not require access, and a helper type/function might require access.

This insight—that the type graph doesn't always reflect the boundaries of concerns—is the very basis of Swift's current access control design. It's the reason why `private` (soon to become `fileprivate`) doesn't grant visibility to extensions on the same type in different files, but *does* grant it to extensions on different types in the same file. This is an important innovation in Swift's access control design, and we shouldn't ignore it when we're thinking about `protected`.

--
Brent Royal-Gordon
Architechies

The purpose of access control isn’t really to keep out malicious users, though, it’s to prevent accidental misuse and clarify the interface.

One nice vector for accidental misuse is autocomplete. Even if layoutSubviews() has a great big // DON’T USE!!! in the documentation, it’s possible that someone is trying to remember the name of the API they need to use to tell the OS something needs to update its layout, so they type “layout” into the code editor, and lo and behold! Here’s something called layoutSubviews() that sounds like the sort of thing we want. And so it goes. A protected modifier in the language would prevent things like this.

Charles

···

On May 30, 2016, at 11:23 AM, Tino Heth <2th@gmx.de> wrote:

Couldn’t you use the same reasoning to claim there shouldn’t be access control at all? Just add documention on methods you want to mark private telling users of the library not to call them!

I guess you are making fun, but actually, good old Objective-C messaging works just that way:
You can call all those dangerous and forbidden private methods easily...
Writing special comments is just one way to document APIs; having no (official) documentation at all is documentation as well ("don't use this!").

Most technical limitations can be cracked by skilled hackers (working around "protected" is especially easy), so I really think that (for example) declaring a method "final" says "I don't want this to be changed in a subclass" in the first place, and the compiler error that is triggered when you try to break the limitation is little more but a remainder.

Enforcing limitations using hacks causes confusion, so I would never use such tricks in production code.

The purpose of access control isn’t really to keep out malicious users, though, it’s to prevent accidental misuse and clarify the interface.

mh, I would call this a "documenting intend" ;-)

One nice vector for accidental misuse is autocomplete. Even if layoutSubviews() has a great big // DON’T USE!!! in the documentation, it’s possible that someone is trying to remember the name of the API they need to use to tell the OS something needs to update its layout, so they type “layout” into the code editor, and lo and behold! Here’s something called layoutSubviews() that sounds like the sort of thing we want. And so it goes. A protected modifier in the language would prevent things like this.

true — but even subclasses shouldn't call layoutSubviews unregulated, so I think this is a flawed example for the usefulness of protected.

I've written up how to provide protected access control for Swift code
today here:

No compiler changes necessary for this technique and it distinguishes
between methods that can only be overridden and methods that can be both
called and overridden.

1 Like

Cool!

-Thorsten

···

Am 30.05.2016 um 06:49 schrieb Callionica (Swift) via swift-evolution <swift-evolution@swift.org>:

I've written up how to provide protected access control for Swift code today here:

Callionica Developer - Programming, Software Development, Architecture

No compiler changes necessary for this technique and it distinguishes between methods that can only be overridden and methods that can be both called and overridden.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That's a nice workaround - but nice in a sense that that it's a hack, not a solution IMHO.

···

On May 30, 2016, at 6:49 AM, Callionica (Swift) via swift-evolution <swift-evolution@swift.org> wrote:

I've written up how to provide protected access control for Swift code today here:

Callionica Developer - Programming, Software Development, Architecture

No compiler changes necessary for this technique and it distinguishes between methods that can only be overridden and methods that can be both called and overridden.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That's a cool hack! For a lighter way to distinguish overridable methods that one shouldn't ordinarily call, did anyone consider approximating "protected" (or as called in Objective-C speak, "private extension") methods with public class methods?

    public class UIView {
        public class func _layoutSubviews(_ view: UIView)
    }

This way, they become overridable, won't show up in the editor auto completion list for a given instance, and can be called… but definitely make you think twice before you do!

— Pyry

···

Callionica (Swift) via swift-evolution <swift-evolution@swift.org> kirjoitti 30.5.2016 kello 7.49:

I've written up how to provide protected access control for Swift code today here:

Callionica Developer - Programming, Software Development, Architecture

No compiler changes necessary for this technique and it distinguishes between methods that can only be overridden and methods that can be both called and overridden.

The purpose of access control isn’t really to keep out malicious users, though, it’s to prevent accidental misuse and clarify the interface.

mh, I would call this a "documenting intend" ;-)

If you get the method as an autocomplete, you won’t see the documentation telling you not to use it.

One nice vector for accidental misuse is autocomplete. Even if layoutSubviews() has a great big // DON’T USE!!! in the documentation, it’s possible that someone is trying to remember the name of the API they need to use to tell the OS something needs to update its layout, so they type “layout” into the code editor, and lo and behold! Here’s something called layoutSubviews() that sounds like the sort of thing we want. And so it goes. A protected modifier in the language would prevent things like this.

true — but even subclasses shouldn't call layoutSubviews unregulated, so I think this is a flawed example for the usefulness of protected.

This is why I prefer fileprivate(call) over protected.

Charles

···

On May 30, 2016, at 2:02 PM, Tino Heth <2th@gmx.de> wrote:

I have to agree with Charlie Monroe that while this is doable, it's clear this is a workaround to a problem, not a viable long term language solution.

- Rod

···

Sent from my iPhone

On 30 May 2016, at 2:49 PM, Callionica (Swift) <swift-callionica@callionica.com> wrote:

I've written up how to provide protected access control for Swift code today here:

Callionica Developer - Programming, Software Development, Architecture

No compiler changes necessary for this technique and it distinguishes between methods that can only be overridden and methods that can be both called and overridden.