[swift-evolution] [Draft] Fix Private Access Levels

Andrey Fidrya af at zabiyaka.com
Wed Mar 1 05:05:55 CST 2017


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

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

For example, I had to split this class into multiple files using extensions:
https://github.com/smud/Smud/blob/master/Sources/Smud/AreaFormatParser/AreaFormatParser.swift <https://github.com/smud/Smud/blob/master/Sources/Smud/AreaFormatParser/AreaFormatParser.swift>
I had to remove 'private' modifier from all variables and functions. Now class implementation details are exposed to the entire module. 'Fileprivate' was of no use in this situation. If there was an ability to mark them as `private to type + extensions`, I would use this access level instead. In fact, in 99% of use cases I needed that exact behavior and not 'internal to module', so I also proposed making it the default.

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

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

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

Regards,
Andrey



> On 21 Feb 2017, at 15:17, David Hart <david at hartbit.com> wrote:
> 
>> 
>> On 21 Feb 2017, at 12:44, Andrey Fidrya <af at zabiyaka.com <mailto:af at zabiyaka.com>> wrote:
>> 
>> >Alternatives Considered:
>> >2. Deprecate fileprivate and modify the semantics of private to include same-type extension scopes in the same module.
>> 
>> Imho, this is a better alternative.
>> 
>> I rarely implement class extensions in the same file. Most often they have their own files, like
>> MyClass+Search.swift
>> MyClass+SomethingElse.swift
>> 
>> Even in cases where implementing them in the same file makes sense, I'm not using current fileprivate modifier on variables because if I later have to implement an extension in a different file, I'll have to remove all these modifiers.
>> 
>> 
>> Also, I don't think internal is a good default choice... Even if private is changed back to mean "file private" or "class private", it will add a lot of visual noise... For proper access limitation, basically everything has to be marked "private". Compare:
>> 
>> class C {
>>   var a = 1
>>   var b = 2
>>   func f() { } 
>> }
>> 
>> to:
>> 
>> class C {
>>   private var a = 1
>>   private var b = 2
>>   private func f() { etc }
>> }
>> 
>> 
>> Also, in classes inheritance is denied by default, but variables have more open 'internal' access level by default.
>> It looks like an inconcistency to me. Users have to explicitly allow inheritance, but disallow access to variables.
>> 
>> 
>> +1 to the arguments about not mixing concepts (file or scope/type based). Personally I'd prefer scope/type only.
>> Also, fileprivate access doesn't play well with playgrounds and makes rearranging code harder.
>> 
>> 
>> If redesigning this from scratch, I'm thinking of this design:
>> 1. scoped (works like the current private)
>> 2. private (to the class + it's extensions inside the module) - and making it the default
>> 3. internal (to the module). Should be set only on variables where it's really needed (will be rarely used).
> 
> In the previous very long thread, many people acknowledged that type + its extensions private was too complex for its own good. Do you have arguments against that? And even if it was proposed, I think many people would be very opposed to keeping scoped in that case. There would be too little difference between the two to be worth it.
> 
>> One more argument for adding "scoped" access level:
>> if it will be allowed to declare variables in extensions of the same module in the future, having "scoped" would be very convenient as there can be multiple extensions in the same file.
>> 
>> 
>> Regards,
>> Andrey
>> 
>> 
>> 
>>> On 21 Feb 2017, at 09:58, David Hart via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at 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 <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 at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170301/c5849180/attachment.html>


More information about the swift-evolution mailing list