[Draft] Fix Private Access Levels

I, too, find all of this churn exhausting - I don’t know how the core team handles it!

That said, I don’t think it is prudent to expect that accepted proposals are final forever. Unintended consequences of any change or combination of changes will always have to be dealt with either by modifying the language or debating our way to a communal rationalization.

l8r
Sean

···

On Feb 21, 2017, at 10:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

I thought that we already had a lengthy discussion about private semantics, naming, etc. All these arguments were already presented during the original proposal discussion and review. At that time I put a lot of time and energy into responding to every email on the subject because I was under impression that unless something changed significantly after the fact, reviews were final. If proposals can be easily reversed later or need to be defended after the fact, I am not sure how many people would be committed enough to do this. As much as I want "private" to mean private, I am not committed enough, if this is what it takes.

I joined the list primarily because I really wanted that change. After it was accepted, I stopped following, partially because I cannot keep up with all the emails. I saw this thread completely by accident when I was going to unsubscribe! I hope to be back when the discussion moves to Discourse, but if accepted proposals are not treated as final decisions (unless something significant comes up), I don't know if I will. I am sure that my absence will not be noticed, but there could be many people like me. People on this list represent a very small percentage of the actual group who use the language, but from what I read here, there seems to be an assumption that people on the list is an accurate representation of the entire group of programmers using Swift. It's not, and there could be a large number of people who silently disagree with any particular proposal, and the actual usage statistics could be different from what people here may think. Also, some people may not know about particular features, and it may be a matter of education rather than a feature not carrying its own weight. If you looked at GitHub, you could say that nobody is using feature X, so it's not useful or needed, but it could also be that if X were publicized better, GitHub would show much more adoption. I really hope that features get decided on the merit of their usefulness and not by vote of people on this list.

I'll wait a day or two to give people a chance to respond and then I'll unsubscribe for now.

On Tue, Feb 21, 2017 at 10:19 AM Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:
> On Feb 21, 2017, at 5:36 AM, Matthew Johnson <matthew@anandabits.com> wrote:
>
> This is true for lexical scoping, but I'd also like to see scoped be parameterized to take the name of a containing scope, such as a containing submodule. This would be a powerful tool that allows sibling submodules to collaborate with each other. It is similar to allowing extensions of different types collaborate within a file, but at a larger level of granularity.

If I correctly understand what you seem to be suggesting, that would mean that access levels would be, ordered from narrowest access to widest, something like:

        scoped
        private
        internal
        scoped(SomeModule, OtherModule)
        public
        open

Having the same keyword appear in two very different places in that list seems...less than ideal.

--
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 shouldn’t be unnecessarily burdened by the opinions of people who feel the need to spend all their time on a mailing list. A language’s features should be useful in their own right. If “nobody" knows how to use a feature appropriately, then random code from GitHub _is_ data that it might not necessarily be well thought out. Proposals can’t be written in stone because we can’t see the future. I’m sorry you no longer want to participate, but the world will keep on turning.

Zachary

···

On Feb 21, 2017, at 11:47 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

I joined the list primarily because I really wanted that change. After it was accepted, I stopped following, partially because I cannot keep up with all the emails. I saw this thread completely by accident when I was going to unsubscribe! I hope to be back when the discussion moves to Discourse, but if accepted proposals are not treated as final decisions (unless something significant comes up), I don't know if I will. I am sure that my absence will not be noticed, but there could be many people like me. People on this list represent a very small percentage of the actual group who use the language, but from what I read here, there seems to be an assumption that people on the list is an accurate representation of the entire group of programmers using Swift. It's not, and there could be a large number of people who silently disagree with any particular proposal, and the actual usage statistics could be different from what people here may think. Also, some people may not know about particular features, and it may be a matter of education rather than a feature not carrying its own weight. If you looked at GitHub, you could say that nobody is using feature X, so it's not useful or needed, but it could also be that if X were publicized better, GitHub would show much more adoption. I really hope that features get decided on the merit of their usefulness and not by vote of people on this list.

>Alternatives Considered:
>2. Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.

Imho, this is a better alternative.

I rarely implement class extensions in the same file. Most often they have their own files, like
MyClass+Search.swift
MyClass+SomethingElse.swift

Even in cases where implementing them in the same file makes sense, I'm not using current fileprivate modifier on variables because if I later have to implement an extension in a different file, I'll have to remove all these modifiers.

Also, I don't think internal is a good default choice... Even if private is changed back to mean "file private" or "class private", it will add a lot of visual noise... For proper access limitation, basically everything has to be marked "private". Compare:

class C {
  var a = 1
  var b = 2
  func f() { }
}

to:

class C {
  private var a = 1
  private var b = 2
  private func f() { etc }
}

Also, in classes inheritance is denied by default, but variables have more open 'internal' access level by default.
It looks like an inconcistency to me. Users have to explicitly allow inheritance, but disallow access to variables.

+1 to the arguments about not mixing concepts (file or scope/type based). Personally I'd prefer scope/type only.
Also, fileprivate access doesn't play well with playgrounds and makes rearranging code harder.

If redesigning this from scratch, I'm thinking of this design:
1. scoped (works like the current private)
2. private (to the class + it's extensions inside the module) - and making it the default
3. internal (to the module). Should be set only on variables where it's really needed (will be rarely used).

In the previous very long thread, many people acknowledged that type + its extensions private was too complex for its own good. Do you have arguments against that? And even if it was proposed, I think many people would be very opposed to keeping scoped in that case. There would be too little difference between the two to be worth it.

···

On 21 Feb 2017, at 12:44, Andrey Fidrya <af@zabiyaka.com> wrote:

One more argument for adding "scoped" access level:
if it will be allowed to declare variables in extensions of the same module in the future, having "scoped" would be very convenient as there can be multiple extensions in the same file.

Regards,
Andrey

On 21 Feb 2017, at 09:58, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello list,

Matthew Johnson and I have been putting our proposals together towards a joint “let’s fix private access levels” proposal. As the community seems quite divided on the issue, we offer two solutions in our proposal to let the community debate and to let the core team make the final decision.

I’d like to concentrate this round of feedback on the quality of the proposal, and not on the merits of Solution 1 or 2. thoughts?

https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals/XXXX-fix-private-access-levels.md

David.

Fix Private Access Levels

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals&gt;
Authors: David Hart <http://github.com/hartbit&gt;, Matthew Johnson <https://github.com/anandabits&gt;
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction&gt;Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt; and presents two community driven solutions to fix them. As a consensus will not easily emerge, this proposal will allow a last round of voting and let the core team decide. Once that is done, this proposal will be ammended to describe the chosen solution.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#motivation&gt;Motivation

Since the release of Swift 3, the access level change of SE-0025 was met with dissatisfaction by a substantial proportion of the general Swift community. Before offering solutions, lets discuss how and why it can be viewed as actiely harmful, the new requirement for syntax/API changes.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#criticisms-of-se-0025&gt;Criticisms of SE-0025

There are two primary criticism that have been offered.

The first is that private is a "soft default" access modifier for restricting access within a file. Scoped access is not a good behavior for a "soft default" because it is extremely common to use several extensions within a file. A "soft default" (and therefore private) should work well with this idiom. It is fair to say that changing the behavior of private such that it does not work well with extensions meets the criteria of actively harmful in the sense that it subtly encourages overuse of scoped access control and discourages the more reasonable default by giving it the awkward name fileprivate.

The second is that Swift's system of access control is too complex. Many people feel like restricting access control to scopes less than a file is of dubious value and therefore wish to simplify Swift's access control story by removing scoped access. However, there are many others who like the ability to have the compiler verify tighter access levels and believe it helps make it easier to reason about code which is protecting invariants.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#detailed-design&gt;Detailed design

Both authors agree that the private keyword should be reverted back to its Swift 2 file-based meaning, resolving the first criticism. But the authors disagree on what should be done about the scoped access level and the following solutions represent the two main opinions in the community:

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-1-remove-the-scoped-access-level&gt;Solution 1: Remove the scoped access level

Compared to a file-based access level, the scoped-based access level adds meaningful information by hiding implementation details which do not concern other types or extensions in the same file. But is that distinction between private and fileprivate actively used by the larger community of Swift developers? And if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language? This solution argues that answer to both questions is no and that the scoped access level should be removed to resolve the complexity criticism.

This solution has the added advantage of leaving the most design breathing-room for future discussions about access levels in regards to submodules.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-2-rename-the-scoped-access-level-to-scoped&gt;Solution 2: Rename the scoped access level to scoped

It is difficult to make the case that a feature which a nontrivial number of Swift users find valuable and which is easy for teams to avoid is actively harmful. It seems like something that falls more into the category of a debate over style (which could be addressed by a linter). Should we remove a feature whose utility is a question of style, but is not actively harmful in the sense of causing programmer error? The second solution argues against it and proposes renaming it to scoped.

The scoped keyword is a good choice not only because the community has been calling this feature “scoped access control” all along, but also because the principle underlying all of Swift’s access levels is the idea of a scope.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#source-compatibility&gt;Source compatibility

In Swift 3 compatibility mode, the compiler will continue to treat private and fileprivate as was previously the case.

In Swift 4 mode, the compiler will deprecate the fileprivate keyword and revert the semantics of the private access level to be file based. The migrator will rename all uses of fileprivate to private. In solution 2, the migrator will also rename all uses of private to scoped.

With solution 1 (and with solution 2 if the migrator is not run), cases where a type had private declarations with the same signature in different scopes will produce a compiler error. For example, the following piece of code compiles in Swift 3 compatibilty mode but generates a Invalid redeclaration of 'foo()' error in Swift 4 mode.

struct Foo {
    private func bar() {}
}

extension Foo {
    private func bar() {}
}
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#alternatives-considered&gt;Alternatives Considered

Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same file.
Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.
The alternatives are potentially interesting but completely remove the file access level while making the new privateaccess level more complicated to explain and understand.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

So, clearly, both of these positions have merit, IMO. For this process to
work, people have to understand that there is a designated time to share
viewpoints surrounding a proposal; then, a decision is taken, and that
decision should be taken as the considered opinion of the Swift community
and core team. Surely, we want to encourage people to write quality prose
to explain their thoughts and ideas to the fullest extent, but no one has
the time or energy to do that repeatedly on the same topic with no end in
sight. Therefore, it's antithetical to fostering an environment of critical
thinking to have the same topic brought up ad nauseam. That's partly
reflected in the existence of a "commonly rejected proposals" document.

Now, of course, if implementation runs into a roadblock, or if real-world
experience after implementation contradicts some fundamental assumptions of
the initial proposal, then revision or retraction may be necessary. But, to
use a legal analogy, that should be the equivalent of re-opening a case
after new evidence comes forward that places the original verdict into
serious doubt. Revisiting a topic should *not* be the equivalent of
appealing a court case after an unfavorable decision.

···

On Tue, Feb 21, 2017 at 11:08 AM, Zach Waldowski via swift-evolution < swift-evolution@swift.org> wrote:

> On Feb 21, 2017, at 11:47 AM, Ilya Belenkiy via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I joined the list primarily because I really wanted that change. After
it was accepted, I stopped following, partially because I cannot keep up
with all the emails. I saw this thread completely by accident when I was
going to unsubscribe! I hope to be back when the discussion moves to
Discourse, but if accepted proposals are not treated as final decisions
(unless something significant comes up), I don't know if I will. I am sure
that my absence will not be noticed, but there could be many people like
me. People on this list represent a very small percentage of the actual
group who use the language, but from what I read here, there seems to be an
assumption that people on the list is an accurate representation of the
entire group of programmers using Swift. It's not, and there could be a
large number of people who silently disagree with any particular proposal,
and the actual usage statistics could be different from what people here
may think. Also, some people may not know about particular features, and it
may be a matter of education rather than a feature not carrying its own
weight. If you looked at GitHub, you could say that nobody is using feature
X, so it's not useful or needed, but it could also be that if X were
publicized better, GitHub would show much more adoption. I really hope that
features get decided on the merit of their usefulness and not by vote of
people on this list.

Swift shouldn’t be unnecessarily burdened by the opinions of people who
feel the need to spend all their time on a mailing list. A language’s
features should be useful in their own right. If “nobody" knows how to use
a feature appropriately, then random code from GitHub _is_ data that it
might not necessarily be well thought out. Proposals can’t be written in
stone because we can’t see the future. I’m sorry you no longer want to
participate, but the world will keep on turning.

I fully agree. I actually think that applies to both solutions though. As much as I would like to see the mess around private fixed, I think it needs to be as part of a well considered redesign of the access system that adds enough functionality to stop this cycle. We can’t just rename things or flip back and forth between options every 6 months.

As an example of what I think *is* an appropriate change is Nevin’s suggestion on another thread to add a single level of submodules (which group files). As part of this change, ‘private’ would mean private to the submodule (or file if the file is not part of a submodule). Internal/Public/Open would remain unchanged. Thus you have only private, internal, and public/open… but the fix came as part of unifying with other improvements (and is not just returning to pre-0025).

Thanks,
Jon

···

On Feb 21, 2017, at 2:41 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Well-written as-is.

Overall, my feedback is that solution 2 should not be on the table (though there are people who clamor for it), and not because I don't agree with it. However, simply as a matter of following an appropriate process, solution 2 was originally proposed in SE-0025, fully considered, and modified by the core team to the current design. One can disagree whether `scoped` is more appropriate than `private` as a name for that access modifier, and one is likely to say that `private` looks nicer than `fileprivate`, but that's neither here nor there. The appropriateness or niceness of these terms is unchanged from last year. Re-submitting SE-0025 cannot be the solution for fixing SE-0025.

Well-written as-is.

Overall, my feedback is that solution 2 should not be on the table (though there are people who clamor for it), and not because I don't agree with it. However, simply as a matter of following an appropriate process, solution 2 was originally proposed in SE-0025, fully considered, and modified by the core team to the current design. One can disagree whether `scoped` is more appropriate than `private` as a name for that access modifier, and one is likely to say that `private` looks nicer than `fileprivate`, but that's neither here nor there. The appropriateness or niceness of these terms is unchanged from last year. Re-submitting SE-0025 cannot be the solution for fixing SE-0025.

I agree with you, as you know that I support Solution 1. But I was hoping to reduce the amount of community flamewar by giving each alternative a level chance and letting the core team decide. But you make a good point about the fact that it was the state SE-0025 was it before it was modified by the core team. And I’m starting to have doubts. What do you think Matthew?

···

On 21 Feb 2017, at 23:41, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Tue, Feb 21, 2017 at 12:58 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
Hello list,

Matthew Johnson and I have been putting our proposals together towards a joint “let’s fix private access levels” proposal. As the community seems quite divided on the issue, we offer two solutions in our proposal to let the community debate and to let the core team make the final decision.

I’d like to concentrate this round of feedback on the quality of the proposal, and not on the merits of Solution 1 or 2. thoughts?

https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals/XXXX-fix-private-access-levels.md

David.

Fix Private Access Levels

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals&gt;
Authors: David Hart <http://github.com/hartbit&gt;, Matthew Johnson <https://github.com/anandabits&gt;
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction&gt;Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt; and presents two community driven solutions to fix them. As a consensus will not easily emerge, this proposal will allow a last round of voting and let the core team decide. Once that is done, this proposal will be ammended to describe the chosen solution.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#motivation&gt;Motivation

Since the release of Swift 3, the access level change of SE-0025 was met with dissatisfaction by a substantial proportion of the general Swift community. Before offering solutions, lets discuss how and why it can be viewed as actiely harmful, the new requirement for syntax/API changes.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#criticisms-of-se-0025&gt;Criticisms of SE-0025

There are two primary criticism that have been offered.

The first is that private is a "soft default" access modifier for restricting access within a file. Scoped access is not a good behavior for a "soft default" because it is extremely common to use several extensions within a file. A "soft default" (and therefore private) should work well with this idiom. It is fair to say that changing the behavior of private such that it does not work well with extensions meets the criteria of actively harmful in the sense that it subtly encourages overuse of scoped access control and discourages the more reasonable default by giving it the awkward name fileprivate.

The second is that Swift's system of access control is too complex. Many people feel like restricting access control to scopes less than a file is of dubious value and therefore wish to simplify Swift's access control story by removing scoped access. However, there are many others who like the ability to have the compiler verify tighter access levels and believe it helps make it easier to reason about code which is protecting invariants.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#detailed-design&gt;Detailed design

Both authors agree that the private keyword should be reverted back to its Swift 2 file-based meaning, resolving the first criticism. But the authors disagree on what should be done about the scoped access level and the following solutions represent the two main opinions in the community:

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-1-remove-the-scoped-access-level&gt;Solution 1: Remove the scoped access level

Compared to a file-based access level, the scoped-based access level adds meaningful information by hiding implementation details which do not concern other types or extensions in the same file. But is that distinction between private and fileprivate actively used by the larger community of Swift developers? And if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language? This solution argues that answer to both questions is no and that the scoped access level should be removed to resolve the complexity criticism.

This solution has the added advantage of leaving the most design breathing-room for future discussions about access levels in regards to submodules.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-2-rename-the-scoped-access-level-to-scoped&gt;Solution 2: Rename the scoped access level to scoped

It is difficult to make the case that a feature which a nontrivial number of Swift users find valuable and which is easy for teams to avoid is actively harmful. It seems like something that falls more into the category of a debate over style (which could be addressed by a linter). Should we remove a feature whose utility is a question of style, but is not actively harmful in the sense of causing programmer error? The second solution argues against it and proposes renaming it to scoped.

The scoped keyword is a good choice not only because the community has been calling this feature “scoped access control” all along, but also because the principle underlying all of Swift’s access levels is the idea of a scope.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#source-compatibility&gt;Source compatibility

In Swift 3 compatibility mode, the compiler will continue to treat private and fileprivate as was previously the case.

In Swift 4 mode, the compiler will deprecate the fileprivate keyword and revert the semantics of the private access level to be file based. The migrator will rename all uses of fileprivate to private. In solution 2, the migrator will also rename all uses of private to scoped.

With solution 1 (and with solution 2 if the migrator is not run), cases where a type had private declarations with the same signature in different scopes will produce a compiler error. For example, the following piece of code compiles in Swift 3 compatibilty mode but generates a Invalid redeclaration of 'foo()' error in Swift 4 mode.

struct Foo {
    private func bar() {}
}

extension Foo {
    private func bar() {}
}
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#alternatives-considered&gt;Alternatives Considered

Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same file.
Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.
The alternatives are potentially interesting but completely remove the file access level while making the new privateaccess level more complicated to explain and understand.

In the previous very long thread, many people acknowledged that type + its extensions private was too complex for its own good. Do you have arguments against that? And even if it was proposed, I think many people would be very opposed to keeping scoped in that case. There would be too little difference between the two to be worth it.

I've been following that thread. Yes, I'll try to present them:

For example, I had to split this class into multiple files using extensions:

I had to remove 'private' modifier from all variables and functions. Now class implementation details are exposed to the entire module. 'Fileprivate' was of no use in this situation. If there was an ability to mark them as `private to type + extensions`, I would use this access level instead. In fact, in 99% of use cases I needed that exact behavior and not 'internal to module', so I also proposed making it the default.

In other words, current visibility system doesn't work for my coding style (splitting classes into multiple files), nor it will work after rolling back private behavior. It could become useful if the concept could be exteded to mean "fileprivate + its extensions private". It would allow protecting other classes in the module from accessing implementation details of the current class. It's sad that many people are opposed to this concept.

On separate 'scoped' access, I agree that it may be redundant.

To summarize, I propose reverting "private" to mean "fileprivate" but extending it to extensions as well. This way both coding styles could be used: putting everything in a single huge file or splitting the class into multiple files or mixing these approaches. Ideally, I think it should be the default access level leaving only "public" and "internal" keywords to be set explicitly.

Regards,
Andrey

···

On 21 Feb 2017, at 15:17, David Hart <david@hartbit.com> wrote:

On 21 Feb 2017, at 12:44, Andrey Fidrya <af@zabiyaka.com <mailto:af@zabiyaka.com>> wrote:

>Alternatives Considered:
>2. Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.

Imho, this is a better alternative.

I rarely implement class extensions in the same file. Most often they have their own files, like
MyClass+Search.swift
MyClass+SomethingElse.swift

Even in cases where implementing them in the same file makes sense, I'm not using current fileprivate modifier on variables because if I later have to implement an extension in a different file, I'll have to remove all these modifiers.

Also, I don't think internal is a good default choice... Even if private is changed back to mean "file private" or "class private", it will add a lot of visual noise... For proper access limitation, basically everything has to be marked "private". Compare:

class C {
  var a = 1
  var b = 2
  func f() { }
}

to:

class C {
  private var a = 1
  private var b = 2
  private func f() { etc }
}

Also, in classes inheritance is denied by default, but variables have more open 'internal' access level by default.
It looks like an inconcistency to me. Users have to explicitly allow inheritance, but disallow access to variables.

+1 to the arguments about not mixing concepts (file or scope/type based). Personally I'd prefer scope/type only.
Also, fileprivate access doesn't play well with playgrounds and makes rearranging code harder.

If redesigning this from scratch, I'm thinking of this design:
1. scoped (works like the current private)
2. private (to the class + it's extensions inside the module) - and making it the default
3. internal (to the module). Should be set only on variables where it's really needed (will be rarely used).

In the previous very long thread, many people acknowledged that type + its extensions private was too complex for its own good. Do you have arguments against that? And even if it was proposed, I think many people would be very opposed to keeping scoped in that case. There would be too little difference between the two to be worth it.

One more argument for adding "scoped" access level:
if it will be allowed to declare variables in extensions of the same module in the future, having "scoped" would be very convenient as there can be multiple extensions in the same file.

Regards,
Andrey

On 21 Feb 2017, at 09:58, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello list,

Matthew Johnson and I have been putting our proposals together towards a joint “let’s fix private access levels” proposal. As the community seems quite divided on the issue, we offer two solutions in our proposal to let the community debate and to let the core team make the final decision.

I’d like to concentrate this round of feedback on the quality of the proposal, and not on the merits of Solution 1 or 2. thoughts?

https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals/XXXX-fix-private-access-levels.md

David.

Fix Private Access Levels

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals&gt;
Authors: David Hart <http://github.com/hartbit&gt;, Matthew Johnson <https://github.com/anandabits&gt;
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction&gt;Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt; and presents two community driven solutions to fix them. As a consensus will not easily emerge, this proposal will allow a last round of voting and let the core team decide. Once that is done, this proposal will be ammended to describe the chosen solution.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#motivation&gt;Motivation

Since the release of Swift 3, the access level change of SE-0025 was met with dissatisfaction by a substantial proportion of the general Swift community. Before offering solutions, lets discuss how and why it can be viewed as actiely harmful, the new requirement for syntax/API changes.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#criticisms-of-se-0025&gt;Criticisms of SE-0025

There are two primary criticism that have been offered.

The first is that private is a "soft default" access modifier for restricting access within a file. Scoped access is not a good behavior for a "soft default" because it is extremely common to use several extensions within a file. A "soft default" (and therefore private) should work well with this idiom. It is fair to say that changing the behavior of private such that it does not work well with extensions meets the criteria of actively harmful in the sense that it subtly encourages overuse of scoped access control and discourages the more reasonable default by giving it the awkward name fileprivate.

The second is that Swift's system of access control is too complex. Many people feel like restricting access control to scopes less than a file is of dubious value and therefore wish to simplify Swift's access control story by removing scoped access. However, there are many others who like the ability to have the compiler verify tighter access levels and believe it helps make it easier to reason about code which is protecting invariants.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#detailed-design&gt;Detailed design

Both authors agree that the private keyword should be reverted back to its Swift 2 file-based meaning, resolving the first criticism. But the authors disagree on what should be done about the scoped access level and the following solutions represent the two main opinions in the community:

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-1-remove-the-scoped-access-level&gt;Solution 1: Remove the scoped access level

Compared to a file-based access level, the scoped-based access level adds meaningful information by hiding implementation details which do not concern other types or extensions in the same file. But is that distinction between private and fileprivate actively used by the larger community of Swift developers? And if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language? This solution argues that answer to both questions is no and that the scoped access level should be removed to resolve the complexity criticism.

This solution has the added advantage of leaving the most design breathing-room for future discussions about access levels in regards to submodules.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-2-rename-the-scoped-access-level-to-scoped&gt;Solution 2: Rename the scoped access level to scoped

It is difficult to make the case that a feature which a nontrivial number of Swift users find valuable and which is easy for teams to avoid is actively harmful. It seems like something that falls more into the category of a debate over style (which could be addressed by a linter). Should we remove a feature whose utility is a question of style, but is not actively harmful in the sense of causing programmer error? The second solution argues against it and proposes renaming it to scoped.

The scoped keyword is a good choice not only because the community has been calling this feature “scoped access control” all along, but also because the principle underlying all of Swift’s access levels is the idea of a scope.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#source-compatibility&gt;Source compatibility

In Swift 3 compatibility mode, the compiler will continue to treat private and fileprivate as was previously the case.

In Swift 4 mode, the compiler will deprecate the fileprivate keyword and revert the semantics of the private access level to be file based. The migrator will rename all uses of fileprivate to private. In solution 2, the migrator will also rename all uses of private to scoped.

With solution 1 (and with solution 2 if the migrator is not run), cases where a type had private declarations with the same signature in different scopes will produce a compiler error. For example, the following piece of code compiles in Swift 3 compatibilty mode but generates a Invalid redeclaration of 'foo()' error in Swift 4 mode.

struct Foo {
    private func bar() {}
}

extension Foo {
    private func bar() {}
}
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#alternatives-considered&gt;Alternatives Considered

Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same file.
Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.
The alternatives are potentially interesting but completely remove the file access level while making the new privateaccess level more complicated to explain and understand.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I support this proposal to restore the file-based meaning of “private”.

This is where I fall on this matter as well.

I've leaned back from all the visibility/submodule discussions because I
haven't had the time to read them in-depth enough to give what I thought
was a fair assessment, but from brief scans of many of them, I find them to
add far too much complexity to the language for little *real* gain.

The most important visibility boundary is outside-module (public) vs.
inside-module (internal); one could argue (as I believe Slava did in
another thread) that everything else is frivolous. I tend to agree with
that, but I would still make special allowances for "private" (in its
original form, meaning file-private) because I've personally found it
valuable in code generation scenarios. Specifically, since Swift modules
are determined by build configurations, we don't have control over which
module our code gets generated into. This means that internal isn't
sufficient—we still want to hide certain parts of that generated code from
other consumers of that code within the same module, and file-private
achieves that perfectly. If someone attempted to circumvent those
protections by adding code to the generated file, it would just get
clobbered the next time the generator runs.

Outside of that, I don't think it's that productive to encourage developers
to finely tune visibility dials that really only serve to protect them from
themselves or teammates.

···

On Mon, Mar 6, 2017 at 1:27 PM Nevin Brackett-Rozinsky via swift-evolution < swift-evolution@swift.org> wrote:

Personally, I do not think we need any more fine-grained access level than
this, so I lean toward solution 1 (remove the scoped access level).
However, I would also be okay with solution 2 (rename the scoped access
level to scoped) if other people have a strong need for it.

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

I support it too, but not because I don’t think finer grain access is not needed, but because it I think was done the wrong way.
I think we should revert to the simple original access modifiers until we got a clear proposal that include submodules, as they are going to be a critical part in defining access level control.

Having fewer access level modifiers until then will reduce the compatibility issues we will have once we want to switch to a better design.

···

Le 6 mars 2017 à 19:27, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> a écrit :

I support this proposal to restore the file-based meaning of “private”.

Personally, I do not think we need any more fine-grained access level than this, so I lean toward solution 1 (remove the scoped access level). However, I would also be okay with solution 2 (rename the scoped access level to scoped) if other people have a strong need for it.

I fully agree. I actually think that applies to both solutions though. As much as I would like to see the mess around private fixed, I think it needs to be as part of a well considered redesign of the access system that adds enough functionality to stop this cycle. We can’t just rename things or flip back and forth between options every 6 months.

As an example of what I think *is* an appropriate change is Nevin’s suggestion on another thread to add a single level of submodules (which group files). As part of this change, ‘private’ would mean private to the submodule (or file if the file is not part of a submodule). Internal/Public/Open would remain unchanged. Thus you have only private, internal, and public/open… but the fix came as part of unifying with other improvements (and is not just returning to pre-0025).

I saw this but it looks very confusing for me: private would mean different things in different contexts and I would have no way to make things private to a file in a submodule.

···

On 22 Feb 2017, at 08:37, Jonathan Hull <jhull@gbis.com> wrote:

Thanks,
Jon

On Feb 21, 2017, at 2:41 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Well-written as-is.

Overall, my feedback is that solution 2 should not be on the table (though there are people who clamor for it), and not because I don't agree with it. However, simply as a matter of following an appropriate process, solution 2 was originally proposed in SE-0025, fully considered, and modified by the core team to the current design. One can disagree whether `scoped` is more appropriate than `private` as a name for that access modifier, and one is likely to say that `private` looks nicer than `fileprivate`, but that's neither here nor there. The appropriateness or niceness of these terms is unchanged from last year. Re-submitting SE-0025 cannot be the solution for fixing SE-0025.

Well-written as-is.

Overall, my feedback is that solution 2 should not be on the table (though there are people who clamor for it), and not because I don't agree with it. However, simply as a matter of following an appropriate process, solution 2 was originally proposed in SE-0025, fully considered, and modified by the core team to the current design. One can disagree whether `scoped` is more appropriate than `private` as a name for that access modifier, and one is likely to say that `private` looks nicer than `fileprivate`, but that's neither here nor there. The appropriateness or niceness of these terms is unchanged from last year. Re-submitting SE-0025 cannot be the solution for fixing SE-0025.

I agree with you, as you know that I support Solution 1. But I was hoping to reduce the amount of community flamewar by giving each alternative a level chance and letting the core team decide. But you make a good point about the fact that it was the state SE-0025 was it before it was modified by the core team. And I’m starting to have doubts. What do you think Matthew?

I’d like to let the submodule discussion simmer a little bit more before commenting on this question. The outcome of that could have a significant impact on what I think we should do about SE-0025. When we put this proposal together I was assuming submodules were going to be out of scope for Swift 4, but it looks like at least the discussion is not. Even if we don’t end up with a formal review of a submodule proposal the discussion might lead to a better idea of what kind of proposal might have a chance to be accepted in the future (by gauging community sentiment in the discussions, etc).

···

On Feb 22, 2017, at 12:32 AM, David Hart <david@hartbit.com> wrote:

On 21 Feb 2017, at 23:41, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

On Tue, Feb 21, 2017 at 12:58 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
Hello list,

Matthew Johnson and I have been putting our proposals together towards a joint “let’s fix private access levels” proposal. As the community seems quite divided on the issue, we offer two solutions in our proposal to let the community debate and to let the core team make the final decision.

I’d like to concentrate this round of feedback on the quality of the proposal, and not on the merits of Solution 1 or 2. thoughts?

https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals/XXXX-fix-private-access-levels.md

David.

Fix Private Access Levels

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals&gt;
Authors: David Hart <http://github.com/hartbit&gt;, Matthew Johnson <https://github.com/anandabits&gt;
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction&gt;Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt; and presents two community driven solutions to fix them. As a consensus will not easily emerge, this proposal will allow a last round of voting and let the core team decide. Once that is done, this proposal will be ammended to describe the chosen solution.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#motivation&gt;Motivation

Since the release of Swift 3, the access level change of SE-0025 was met with dissatisfaction by a substantial proportion of the general Swift community. Before offering solutions, lets discuss how and why it can be viewed as actiely harmful, the new requirement for syntax/API changes.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#criticisms-of-se-0025&gt;Criticisms of SE-0025

There are two primary criticism that have been offered.

The first is that private is a "soft default" access modifier for restricting access within a file. Scoped access is not a good behavior for a "soft default" because it is extremely common to use several extensions within a file. A "soft default" (and therefore private) should work well with this idiom. It is fair to say that changing the behavior of private such that it does not work well with extensions meets the criteria of actively harmful in the sense that it subtly encourages overuse of scoped access control and discourages the more reasonable default by giving it the awkward name fileprivate.

The second is that Swift's system of access control is too complex. Many people feel like restricting access control to scopes less than a file is of dubious value and therefore wish to simplify Swift's access control story by removing scoped access. However, there are many others who like the ability to have the compiler verify tighter access levels and believe it helps make it easier to reason about code which is protecting invariants.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#detailed-design&gt;Detailed design

Both authors agree that the private keyword should be reverted back to its Swift 2 file-based meaning, resolving the first criticism. But the authors disagree on what should be done about the scoped access level and the following solutions represent the two main opinions in the community:

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-1-remove-the-scoped-access-level&gt;Solution 1: Remove the scoped access level

Compared to a file-based access level, the scoped-based access level adds meaningful information by hiding implementation details which do not concern other types or extensions in the same file. But is that distinction between private and fileprivate actively used by the larger community of Swift developers? And if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language? This solution argues that answer to both questions is no and that the scoped access level should be removed to resolve the complexity criticism.

This solution has the added advantage of leaving the most design breathing-room for future discussions about access levels in regards to submodules.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-2-rename-the-scoped-access-level-to-scoped&gt;Solution 2: Rename the scoped access level to scoped

It is difficult to make the case that a feature which a nontrivial number of Swift users find valuable and which is easy for teams to avoid is actively harmful. It seems like something that falls more into the category of a debate over style (which could be addressed by a linter). Should we remove a feature whose utility is a question of style, but is not actively harmful in the sense of causing programmer error? The second solution argues against it and proposes renaming it to scoped.

The scoped keyword is a good choice not only because the community has been calling this feature “scoped access control” all along, but also because the principle underlying all of Swift’s access levels is the idea of a scope.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#source-compatibility&gt;Source compatibility

In Swift 3 compatibility mode, the compiler will continue to treat private and fileprivate as was previously the case.

In Swift 4 mode, the compiler will deprecate the fileprivate keyword and revert the semantics of the private access level to be file based. The migrator will rename all uses of fileprivate to private. In solution 2, the migrator will also rename all uses of private to scoped.

With solution 1 (and with solution 2 if the migrator is not run), cases where a type had private declarations with the same signature in different scopes will produce a compiler error. For example, the following piece of code compiles in Swift 3 compatibilty mode but generates a Invalid redeclaration of 'foo()' error in Swift 4 mode.

struct Foo {
    private func bar() {}
}

extension Foo {
    private func bar() {}
}
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#alternatives-considered&gt;Alternatives Considered

Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same file.
Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.
The alternatives are potentially interesting but completely remove the file access level while making the new privateaccess level more complicated to explain and understand.

I fully agree. I actually think that applies to both solutions though. As much as I would like to see the mess around private fixed, I think it needs to be as part of a well considered redesign of the access system that adds enough functionality to stop this cycle. We can’t just rename things or flip back and forth between options every 6 months.

As an example of what I think *is* an appropriate change is Nevin’s suggestion on another thread to add a single level of submodules (which group files). As part of this change, ‘private’ would mean private to the submodule (or file if the file is not part of a submodule). Internal/Public/Open would remain unchanged. Thus you have only private, internal, and public/open… but the fix came as part of unifying with other improvements (and is not just returning to pre-0025).

I saw this but it looks very confusing for me: private would mean different things in different contexts and I would have no way to make things private to a file in a submodule.

Nor would you have a way to make things private to a particular scope. Private would always mean private to the submodule (and files without an explicit submodule would be an implicit anonymous submodule). I like the simplicity. You can basically think of it as Swift 2 private, but with the allowance to split things up into multiple files.

Anyway, my main point (regardless of what people think of that particular proposal) is that we need to fix the underlying issues with access (not just rehash 0025).

Thanks,
Jon

···

On Feb 21, 2017, at 11:47 PM, David Hart <david@hartbit.com> wrote:

On 22 Feb 2017, at 08:37, Jonathan Hull <jhull@gbis.com> wrote:

Thanks,
Jon

On Feb 21, 2017, at 2:41 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Well-written as-is.

Overall, my feedback is that solution 2 should not be on the table (though there are people who clamor for it), and not because I don't agree with it. However, simply as a matter of following an appropriate process, solution 2 was originally proposed in SE-0025, fully considered, and modified by the core team to the current design. One can disagree whether `scoped` is more appropriate than `private` as a name for that access modifier, and one is likely to say that `private` looks nicer than `fileprivate`, but that's neither here nor there. The appropriateness or niceness of these terms is unchanged from last year. Re-submitting SE-0025 cannot be the solution for fixing SE-0025.

I fully agree. I actually think that applies to both solutions
though. As much as I would like to see the mess around private
fixed, I think it needs to be as part of a well considered redesign
of the access system that adds enough functionality to stop this
cycle. We can’t just rename things or flip back and forth between
options every 6 months.

As an example of what I think *is* an appropriate change is Nevin’s
suggestion on another thread to add a single level of submodules
(which group files). As part of this change, ‘private’ would mean
private to the submodule (or file if the file is not part of a
submodule). Internal/Public/Open would remain unchanged. Thus you
have only private, internal, and public/open… but the fix came as
part of unifying with other improvements (and is not just returning
to pre-0025).

I saw this but it looks very confusing for me: private would mean
different things in different contexts and I would have no way to make
things private to a file in a submodule.

Nor would you have a way to make things private to a particular scope.
Private would always mean private to the submodule (and files without an
explicit submodule would be an implicit anonymous submodule). I like the
simplicity. You can basically think of it as Swift 2 private, but with
the allowance to split things up into multiple files.

Anyway, my main point (regardless of what people think of that
particular proposal) is that we need to fix the underlying issues with
access (not just rehash 0025).

Yes, I believe we all(most of us) agree "we need to fix", but in different ways.
And while one thinks of 'simplicity' as more easy way to *write* the code(don't need to think about access levels), other thinks as more easy way to *use* and *support* code(own or other's), when you can attentively configure access levels and get help from compiler in case one (even by mistake) is touching what was *not designed* to be touched.

no well-designed scoped access modifiers in addition to module/file access levels. I do think they are two axis of the access control/documentation, and should work together to aim the better code quality and 'simplicity' in all meanings.

The one way I can think of scoped access modifiers is that they should have explicit and clear naming, even if this will lead to more massive syntax (like Matthew Johnson suggested scoped(scopeName)). While keep public/internal/private(as was in Swift2) names simple and easy to use.

for example,
// File.swift
class C {
  scoped(type) var veryPrivateProp1 = 1
  public scoped(type:set) var veryPrivateProp2 = 2
  scoped(subtype) var akaProtectedProp3 = 3
  scoped(extension) var accessFromSubtypeAndExtension = 4

  // as it is common to give access to internals inside the same
  // file, IMO we need also this:
  scoped(file,subtype) var insideThisFileAndSubtypes = 5
  scoped(file,extension) var insideThisFileAndSubtypeAndExtension = 6
  
  // as a variant, currently "friend" means any code inside the file:
  //scoped(friend,subtype) ...
  //scoped(friend,extension) ...

  // ex: property, that can be changed only inside this type or
  // subtype, but can be accessed from extensions and inside this
  // file
  scoped(file,extensions) scoped(type,subtype:set) var myProp = 7
}

Just as the "food for thoughts"..

···

On 22.02.2017 11:26, Jonathan Hull via swift-evolution wrote:

On Feb 21, 2017, at 11:47 PM, David Hart <david@hartbit.com> wrote:

On 22 Feb 2017, at 08:37, Jonathan Hull <jhull@gbis.com> wrote:

From my point of view the "underlying issues with access" is that we have

Thanks, Jon

Thanks, Jon

On Feb 21, 2017, at 2:41 PM, Xiaodi Wu via swift-evolution >>>> <swift-evolution@swift.org> wrote:

Well-written as-is.

Overall, my feedback is that solution 2 should not be on the table
(though there are people who clamor for it), and not because I
don't agree with it. However, simply as a matter of following an
appropriate process, solution 2 was originally proposed in
SE-0025, fully considered, and modified by the core team to the
current design. One can disagree whether `scoped` is more
appropriate than `private` as a name for that access modifier, and
one is likely to say that `private` looks nicer than
`fileprivate`, but that's neither here nor there. The
appropriateness or niceness of these terms is unchanged from last
year. Re-submitting SE-0025 cannot be the solution for fixing
SE-0025.

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

Well-written as-is.

Overall, my feedback is that solution 2 should not be on the table (though there are people who clamor for it), and not because I don't agree with it. However, simply as a matter of following an appropriate process, solution 2 was originally proposed in SE-0025, fully considered, and modified by the core team to the current design. One can disagree whether `scoped` is more appropriate than `private` as a name for that access modifier, and one is likely to say that `private` looks nicer than `fileprivate`, but that's neither here nor there. The appropriateness or niceness of these terms is unchanged from last year. Re-submitting SE-0025 cannot be the solution for fixing SE-0025.

I agree with you, as you know that I support Solution 1. But I was hoping to reduce the amount of community flamewar by giving each alternative a level chance and letting the core team decide. But you make a good point about the fact that it was the state SE-0025 was it before it was modified by the core team. And I’m starting to have doubts. What do you think Matthew?

I’d like to let the submodule discussion simmer a little bit more before commenting on this question. The outcome of that could have a significant impact on what I think we should do about SE-0025. When we put this proposal together I was assuming submodules were going to be out of scope for Swift 4, but it looks like at least the discussion is not. Even if we don’t end up with a formal review of a submodule proposal the discussion might lead to a better idea of what kind of proposal might have a chance to be accepted in the future (by gauging community sentiment in the discussions, etc).

Ok, lets give it a little while.

···

On 22 Feb 2017, at 16:33, Matthew Johnson <matthew@anandabits.com> wrote:

On Feb 22, 2017, at 12:32 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

On 21 Feb 2017, at 23:41, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

On Tue, Feb 21, 2017 at 12:58 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
Hello list,

Matthew Johnson and I have been putting our proposals together towards a joint “let’s fix private access levels” proposal. As the community seems quite divided on the issue, we offer two solutions in our proposal to let the community debate and to let the core team make the final decision.

I’d like to concentrate this round of feedback on the quality of the proposal, and not on the merits of Solution 1 or 2. thoughts?

https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals/XXXX-fix-private-access-levels.md

David.

Fix Private Access Levels

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/fix-private-access-levels/proposals&gt;
Authors: David Hart <http://github.com/hartbit&gt;, Matthew Johnson <https://github.com/anandabits&gt;
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction&gt;Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt; and presents two community driven solutions to fix them. As a consensus will not easily emerge, this proposal will allow a last round of voting and let the core team decide. Once that is done, this proposal will be ammended to describe the chosen solution.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#motivation&gt;Motivation

Since the release of Swift 3, the access level change of SE-0025 was met with dissatisfaction by a substantial proportion of the general Swift community. Before offering solutions, lets discuss how and why it can be viewed as actiely harmful, the new requirement for syntax/API changes.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#criticisms-of-se-0025&gt;Criticisms of SE-0025

There are two primary criticism that have been offered.

The first is that private is a "soft default" access modifier for restricting access within a file. Scoped access is not a good behavior for a "soft default" because it is extremely common to use several extensions within a file. A "soft default" (and therefore private) should work well with this idiom. It is fair to say that changing the behavior of private such that it does not work well with extensions meets the criteria of actively harmful in the sense that it subtly encourages overuse of scoped access control and discourages the more reasonable default by giving it the awkward name fileprivate.

The second is that Swift's system of access control is too complex. Many people feel like restricting access control to scopes less than a file is of dubious value and therefore wish to simplify Swift's access control story by removing scoped access. However, there are many others who like the ability to have the compiler verify tighter access levels and believe it helps make it easier to reason about code which is protecting invariants.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#detailed-design&gt;Detailed design

Both authors agree that the private keyword should be reverted back to its Swift 2 file-based meaning, resolving the first criticism. But the authors disagree on what should be done about the scoped access level and the following solutions represent the two main opinions in the community:

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-1-remove-the-scoped-access-level&gt;Solution 1: Remove the scoped access level

Compared to a file-based access level, the scoped-based access level adds meaningful information by hiding implementation details which do not concern other types or extensions in the same file. But is that distinction between private and fileprivate actively used by the larger community of Swift developers? And if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language? This solution argues that answer to both questions is no and that the scoped access level should be removed to resolve the complexity criticism.

This solution has the added advantage of leaving the most design breathing-room for future discussions about access levels in regards to submodules.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#solution-2-rename-the-scoped-access-level-to-scoped&gt;Solution 2: Rename the scoped access level to scoped

It is difficult to make the case that a feature which a nontrivial number of Swift users find valuable and which is easy for teams to avoid is actively harmful. It seems like something that falls more into the category of a debate over style (which could be addressed by a linter). Should we remove a feature whose utility is a question of style, but is not actively harmful in the sense of causing programmer error? The second solution argues against it and proposes renaming it to scoped.

The scoped keyword is a good choice not only because the community has been calling this feature “scoped access control” all along, but also because the principle underlying all of Swift’s access levels is the idea of a scope.

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#source-compatibility&gt;Source compatibility

In Swift 3 compatibility mode, the compiler will continue to treat private and fileprivate as was previously the case.

In Swift 4 mode, the compiler will deprecate the fileprivate keyword and revert the semantics of the private access level to be file based. The migrator will rename all uses of fileprivate to private. In solution 2, the migrator will also rename all uses of private to scoped.

With solution 1 (and with solution 2 if the migrator is not run), cases where a type had private declarations with the same signature in different scopes will produce a compiler error. For example, the following piece of code compiles in Swift 3 compatibilty mode but generates a Invalid redeclaration of 'foo()' error in Swift 4 mode.

struct Foo {
    private func bar() {}
}

extension Foo {
    private func bar() {}
}
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#alternatives-considered&gt;Alternatives Considered

Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same file.
Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.
The alternatives are potentially interesting but completely remove the file access level while making the new privateaccess level more complicated to explain and understand.