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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution