[Draft] Fix Private Access Levels


(David Hart) #1

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>
Authors: David Hart <http://github.com/hartbit>, Matthew Johnson <https://github.com/anandabits>
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>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.


(Jon Hull) #2

I believe the actual problem is with ‘internal’, and that our problems with private are a symptom of that deeper issue. We need to fix the deeper underlying issue.

From this blog post (https://developer.apple.com/swift/blog/?id=11), it seems Internal was meant to share parts of types which should be internal to the type, but need to be shared with related types. The issue is that, because internal is the default, it doesn’t express authorial intent about the internal-ness of a given member, and it feels too open not to be accidentally used (especially inside an app, where it is essentially the same as public).

What we need is a way for the author to express: "This is internal to the type, don’t mess with it unnecessarily” while still allowing (opt-in?) access when necessary. Swift 2’s private did a pretty good job of that, allowing anything that was located together to see each other’s internal bits, but because it only worked for one file it results in super long files. The idea of location based sharing is a good one though and is simple to teach.

I think that larger context needs to be examined when considering what to do here. For example, perhaps the answer is replacing fileprivate a module system (if it can be done without adding too much complexity). My ideal solution would unify access modifiers back to a single concept (either file or scope/type based, but not both).

Thanks,
Jon

···

On Feb 20, 2017, at 10:58 PM, David Hart via swift-evolution <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>
Authors: David Hart <http://github.com/hartbit>, Matthew Johnson <https://github.com/anandabits>
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>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
https://lists.swift.org/mailman/listinfo/swift-evolution


(BJ Homer) #3

This sentence in the Motivation sentence is confusing:

    Before offering solutions, lets discuss how and why it can be viewed as actiely harmful, the new requirement for syntax/API changes.

I would suggest rewording it as follows:
  
    Before offering solution, let’s discuss how and why it can be viewed as actively harmful (which is the new requirement for syntax/API changes.)

My initial parsing of this sentence was “let’s discuss how the new requirement for syntax/API changes can be viewed as actively harmful”, which is not the intended meaning.

-BJ

···

On Feb 20, 2017, at 11:58 PM, David Hart via swift-evolution <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>
Authors: David Hart <http://github.com/hartbit>, Matthew Johnson <https://github.com/anandabits>
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>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
https://lists.swift.org/mailman/listinfo/swift-evolution


(Brent Royal-Gordon) #4

I think the second part of this sentence undermines the argument for `scoped` as a keyword: if *all* access levels are about scope, then *this* access level should not be called `scoped`, because the keyword should describe what's *different* about this access level.

That's not to say "scoped" is a bad name, but I think it's good because the space inside curly braces can be thought of as a "scope". So I'd revise this sentence to something like:

  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 a variable's scope is traditionally restrained to the curly-brace-delimited block the variable is declared in, and that's the behavior `scoped` implements.

···

On Feb 20, 2017, at 10:58 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

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.

--
Brent Royal-Gordon
Architechies


(Brent Royal-Gordon) #5

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.

···

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.

--
Brent Royal-Gordon
Architechies


(Matthew Johnson) #6

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.

I think the second part of this sentence undermines the argument for `scoped` as a keyword: if *all* access levels are about scope, then *this* access level should not be called `scoped`, because the keyword should describe what's *different* about this access level.

I disagree Brent. Maybe this statement will make more sense after I share my thoughts on how I want scope to work with submodules.

That's not to say "scoped" is a bad name, but I think it's good because the space inside curly braces can be thought of as a "scope". So I'd revise this sentence to something like:

   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 a variable's scope is traditionally restrained to the curly-brace-delimited block the variable is declared in, and that's the behavior `scoped` implements.

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.

···

Sent from my iPad
On Feb 21, 2017, at 4:40 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 20, 2017, at 10:58 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

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


(Rien) #7

I don’t know if you want to add this to the ‘criticism’ or not.

1) The information content added by “fileprivate” is questionable because of the ‘soft default’:

- People will switch from private to fileprivate without much thought if that is desirable or not.
- Other people will default to ‘fileprivate’, necessary or not.

2) Since the difference between ‘fileprivate’ and ‘private’ only works within a file, anybody who is affected by it also has the possibility to change it from one to the other. Making the distinction between them rather arbitrary. Teams relying on the distinction may find themselves in a place where a developer changed private to fileprivate for a quick investigation/solution, and forgetting to revert the change before committing his solution. This error might remain undiscovered until several revisions later (or never).

3) Mixing scope and file based access levels makes the entire access level concept hard to understand.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

···

On 21 Feb 2017, at 07:58, David Hart via swift-evolution <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
  • Authors: David Hart, Matthew Johnson
  • Review Manager: TBD
  • Status: TBD
Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 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.

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.

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.

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:

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.

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.

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
() {}
}

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
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Hart) #8

I believe the actual problem is with ‘internal’, and that our problems with private are a symptom of that deeper issue. We need to fix the deeper underlying issue.

From this blog post (https://developer.apple.com/swift/blog/?id=11 <https://developer.apple.com/swift/blog/?id=11>), it seems Internal was meant to share parts of types which should be internal to the type, but need to be shared with related types.

What gives you that impression? I’ve never had that impression.

The issue is that, because internal is the default, it doesn’t express authorial intent about the internal-ness of a given member, and it feels too open not to be accidentally used (especially inside an app, where it is essentially the same as public).

I don’t agree. It represents a sane default that makes it easy for single-module applications to share all types together, while hiding members which need to be with private, and at the same time being a sane default for a library which should only thoughtfully render types/members public.

···

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

What we need is a way for the author to express: "This is internal to the type, don’t mess with it unnecessarily” while still allowing (opt-in?) access when necessary. Swift 2’s private did a pretty good job of that, allowing anything that was located together to see each other’s internal bits, but because it only worked for one file it results in super long files. The idea of location based sharing is a good one though and is simple to teach.

I think that larger context needs to be examined when considering what to do here. For example, perhaps the answer is replacing fileprivate a module system (if it can be done without adding too much complexity). My ideal solution would unify access modifiers back to a single concept (either file or scope/type based, but not both).

Thanks,
Jon

On Feb 20, 2017, at 10:58 PM, 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>
Authors: David Hart <http://github.com/hartbit>, Matthew Johnson <https://github.com/anandabits>
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>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


(Matthew Johnson) #9

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.

That's not exactly how I see it working. I'll cover this in my take on submodules.

···

Sent from my iPhone
On Feb 21, 2017, at 9:18 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Feb 21, 2017, at 5:36 AM, Matthew Johnson <matthew@anandabits.com> wrote:

--
Brent Royal-Gordon
Architechies


(David Hart) #10

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.

I think the second part of this sentence undermines the argument for `scoped` as a keyword: if *all* access levels are about scope, then *this* access level should not be called `scoped`, because the keyword should describe what's *different* about this access level.

That's not to say "scoped" is a bad name, but I think it's good because the space inside curly braces can be thought of as a "scope". So I'd revise this sentence to something like:

  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 a variable's scope is traditionally restrained to the curly-brace-delimited block the variable is declared in, and that's the behavior `scoped` implements.

I totally agree with you :slight_smile: But that’s the part of the proposal that Matthew Johnson is supporting. If you come to an agreement, I’ll update the proposal.

···

On 21 Feb 2017, at 11:40, Brent Royal-Gordon <brent@architechies.com> wrote:

On Feb 20, 2017, at 10:58 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies


(Andrey Fidrya) #11

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

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> 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>
Authors: David Hart <http://github.com/hartbit>, Matthew Johnson <https://github.com/anandabits>
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>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
https://lists.swift.org/mailman/listinfo/swift-evolution


(Xiaodi Wu) #12

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.

···

On Tue, Feb 21, 2017 at 12:58 AM, David Hart <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>
   - Authors: David Hart <http://github.com/hartbit>, Matthew Johnson
   <https://github.com/anandabits>
   - Review Manager: TBD
   - Status: TBD

<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>
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> 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>
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>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>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>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>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>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>Alternatives
Considered

   1. Deprecate fileprivate and modify the semantics of private to
   include same-type extension scopes in the same file.
   2. 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.


(Ilya Belenkiy) #13

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


(Vladimir) #14

FWIW, I do think "Solution 2: Rename the scoped access level to scoped" is the best solution. It has(like current 'private') a value of protecting (even from yourself) with compiler's help access to very internal details of type, which must not be accessed anywhere else for ex. by mistake/autocompletion, even in extension/in subclass/in the same file.

Even having at some moment submodules in Swift(where we can use 'internal' to provide details for extensions in other files, but at the same time hide details outside of submodule), IMO we need 'scoped' access level inside submodule for the same reasons.

Also, 'scoped' can be extended in future, like scoped(subtype), scoped(extension), scoped(futureScope) or other variants (for example to represent some kind of 'protected' if we'll decide to have it).

I'd suggest add this to the Solution 2 proposal: 'scoped' access modifier can not be used (how to describe this better...) in global scope i.e. outside of type declaration, to remove one point of ambiguity.
So, there should be no possibility to mark type/func/var as scoped like here:
// File.swift
scoped class MyClass {} // not allowed, only private allowed here
private class MyClass {} // ok, "private to file"

And IMO it is weird to change access modifiers in Swift3, provide new scoped access, and then in Swift4, not just rename but remove that access level. New access level was massively discussed, it was not accepted fast or without considerations of other directions. Many found current 'private' helpful in code organization, they already built their rules/styles with using of this access level. Someone who don't like it - just don't use it.

Currently we can refine "base" access modifiers(revert to public/internal/private) and keep new access level('scoped'). With the perspective to have more granulated scoped levels. This is the right direction I believe.

(personally I still think we additionally need "the same file and subclasses/extensions in other files inside the module" access level, which has a value of distributing coupled code by a number of files, to not keep all such code in the same huge file, which can be accessed by a number of devs in team. Matthew, didn't you considered this direction also?)

···

On 21.02.2017 9:58, David Hart via swift-evolution 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>
  * Authors: David Hart <http://github.com/hartbit>, Matthew Johnson
    <https://github.com/anandabits>
  * Review Manager: TBD
  * Status: TBD

    <https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>Alternatives
    Considered

1. Deprecate |fileprivate| and modify the semantics of |private| to
    include same-type extension scopes in the same file.
2. 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 |private|access level more complicated to
explain and understand.

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


#15

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.

Nevin


(Jon Hull) #16

I am not arguing that internal shouldn’t be the default… just that we need something else to fill the void that is created by having it be the default. That could be submodules, it could be ‘hidden’, it could be something else…

I am saying we need to take a wider view and look at what is actually bothering people. Just renaming things won’t solve the underlying issue…

We need to come up with a cohesive story around access modifiers.

Thanks,
Jon

···

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

On 21 Feb 2017, at 08:36, Jonathan Hull <jhull@gbis.com <mailto:jhull@gbis.com>> wrote:

I believe the actual problem is with ‘internal’, and that our problems with private are a symptom of that deeper issue. We need to fix the deeper underlying issue.

From this blog post (https://developer.apple.com/swift/blog/?id=11 <https://developer.apple.com/swift/blog/?id=11>), it seems Internal was meant to share parts of types which should be internal to the type, but need to be shared with related types.

What gives you that impression? I’ve never had that impression.

The issue is that, because internal is the default, it doesn’t express authorial intent about the internal-ness of a given member, and it feels too open not to be accidentally used (especially inside an app, where it is essentially the same as public).

I don’t agree. It represents a sane default that makes it easy for single-module applications to share all types together, while hiding members which need to be with private, and at the same time being a sane default for a library which should only thoughtfully render types/members public.

What we need is a way for the author to express: "This is internal to the type, don’t mess with it unnecessarily” while still allowing (opt-in?) access when necessary. Swift 2’s private did a pretty good job of that, allowing anything that was located together to see each other’s internal bits, but because it only worked for one file it results in super long files. The idea of location based sharing is a good one though and is simple to teach.

I think that larger context needs to be examined when considering what to do here. For example, perhaps the answer is replacing fileprivate a module system (if it can be done without adding too much complexity). My ideal solution would unify access modifiers back to a single concept (either file or scope/type based, but not both).

Thanks,
Jon

On Feb 20, 2017, at 10:58 PM, 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>
Authors: David Hart <http://github.com/hartbit>, Matthew Johnson <https://github.com/anandabits>
Review Manager: TBD
Status: TBD
<https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>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


(Matthew Johnson) #17

I don’t know if you want to add this to the ‘criticism’ or not.

1) The information content added by “fileprivate” is questionable because of the ‘soft default’:

- People will switch from private to fileprivate without much thought if that is desirable or not.
- Other people will default to ‘fileprivate’, necessary or not.

2) Since the difference between ‘fileprivate’ and ‘private’ only works within a file, anybody who is affected by it also has the possibility to change it from one to the other. Making the distinction between them rather arbitrary. Teams relying on the distinction may find themselves in a place where a developer changed private to fileprivate for a quick investigation/solution, and forgetting to revert the change before committing his solution. This error might remain undiscovered until several revisions later (or never).

3) Mixing scope and file based access levels makes the entire access level concept hard to understand.

But a file is a scope, so in that sense it's not mixing too separate concepts. Now that the submodule discussion has heated up I'm going to share some thoughts on how I want to see `scoped` be enhanced to support encapsulation by allowing it to accept the name of a containing scope, which could be broader than a file (a submodule). I'm very busy today so this probably won't happen until tomorrow.

···

Sent from my iPad

On Feb 21, 2017, at 1:47 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 21 Feb 2017, at 07:58, David Hart via swift-evolution <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
   • Authors: David Hart, Matthew Johnson
   • Review Manager: TBD
   • Status: TBD
Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 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.

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.

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.

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:

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.

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.

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
() {}
}

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
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Matthew Johnson) #18

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.

I think the second part of this sentence undermines the argument for `scoped` as a keyword: if *all* access levels are about scope, then *this* access level should not be called `scoped`, because the keyword should describe what's *different* about this access level.

That's not to say "scoped" is a bad name, but I think it's good because the space inside curly braces can be thought of as a "scope". So I'd revise this sentence to something like:

   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 a variable's scope is traditionally restrained to the curly-brace-delimited block the variable is declared in, and that's the behavior `scoped` implements.

I totally agree with you :slight_smile: But that’s the part of the proposal that Matthew Johnson is supporting. If you come to an agreement, I’ll update the proposal.

I'll give some thought to rewording this section as soon as I can. Possibly tonight, possibly tomorrow.

···

Sent from my iPad

On Feb 21, 2017, at 5:45 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

On 21 Feb 2017, at 11:40, Brent Royal-Gordon <brent@architechies.com> wrote:
On Feb 20, 2017, at 10:58 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

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


(Matthew Johnson) #19

FWIW, I do think "Solution 2: Rename the scoped access level to scoped" is the best solution. It has(like current 'private') a value of protecting (even from yourself) with compiler's help access to very internal details of type, which must not be accessed anywhere else for ex. by mistake/autocompletion, even in extension/in subclass/in the same file.

Even having at some moment submodules in Swift(where we can use 'internal' to provide details for extensions in other files, but at the same time hide details outside of submodule), IMO we need 'scoped' access level inside submodule for the same reasons.

Also, 'scoped' can be extended in future, like scoped(subtype), scoped(extension), scoped(futureScope) or other variants (for example to represent some kind of 'protected' if we'll decide to have it).

I'd suggest add this to the Solution 2 proposal: 'scoped' access modifier can not be used (how to describe this better...) in global scope i.e. outside of type declaration, to remove one point of ambiguity.
So, there should be no possibility to mark type/func/var as scoped like here:
// File.swift
scoped class MyClass {} // not allowed, only private allowed here
private class MyClass {} // ok, "private to file"

And IMO it is weird to change access modifiers in Swift3, provide new scoped access, and then in Swift4, not just rename but remove that access level. New access level was massively discussed, it was not accepted fast or without considerations of other directions. Many found current 'private' helpful in code organization, they already built their rules/styles with using of this access level. Someone who don't like it - just don't use it.

Currently we can refine "base" access modifiers(revert to public/internal/private) and keep new access level('scoped'). With the perspective to have more granulated scoped levels. This is the right direction I believe.

(personally I still think we additionally need "the same file and subclasses/extensions in other files inside the module" access level, which has a value of distributing coupled code by a number of files, to not keep all such code in the same huge file, which can be accessed by a number of devs in team. Matthew, didn't you considered this direction also?)

Now that the submodules discussion is active I'm going to share my thoughts on it, including how I see `scoped` playing a role, as soon as I have a chance to write them up. It will take a day or two to do this. I'm pretty busy right now and want to relate my ideas to other ideas that have been shared thus far. Stay tuned!

···

Sent from my iPhone

On Feb 21, 2017, at 7:51 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

On 21.02.2017 9:58, David Hart via swift-evolution 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>
* Authors: David Hart <http://github.com/hartbit>, Matthew Johnson
   <https://github.com/anandabits>
* Review Manager: TBD
* Status: TBD

   <https://github.com/hartbit/swift-evolution/tree/fix-private-access-levels#introduction>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> 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>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>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>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>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>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>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>Alternatives
   Considered

1. Deprecate |fileprivate| and modify the semantics of |private| to
   include same-type extension scopes in the same file.
2. 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 |private|access level more complicated to
explain and understand.

_______________________________________________
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


(David Hart) #20

I don’t know if you want to add this to the ‘criticism’ or not.

1) The information content added by “fileprivate” is questionable because of the ‘soft default’:

- People will switch from private to fileprivate without much thought if that is desirable or not.
- Other people will default to ‘fileprivate’, necessary or not.

2) Since the difference between ‘fileprivate’ and ‘private’ only works within a file, anybody who is affected by it also has the possibility to change it from one to the other. Making the distinction between them rather arbitrary. Teams relying on the distinction may find themselves in a place where a developer changed private to fileprivate for a quick investigation/solution, and forgetting to revert the change before committing his solution. This error might remain undiscovered until several revisions later (or never).

3) Mixing scope and file based access levels makes the entire access level concept hard to understand.

They are all good points. I’ll integrate the ideas in the next version.

···

On 21 Feb 2017, at 08:47, Rien <Rien@Balancingrock.nl> wrote:

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 21 Feb 2017, at 07:58, David Hart via swift-evolution <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
  • Authors: David Hart, Matthew Johnson
  • Review Manager: TBD
  • Status: TBD
Introduction

This proposal presents the problems the came with the the access level modifications in SE-0025 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.

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.

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.

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:

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.

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.

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
() {}
}

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
https://lists.swift.org/mailman/listinfo/swift-evolution