General impression is positive in case shortcuts (private, bulblic) still remain for the most common use cases.
On Thu, 2 Mar 2017 at 21:58 Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote: > I’ve been continuing to think about how to provide clear and consistent > semantics for access control in Swift. This draft represents what I think > is the best way to accomplish that. It eliminates the current > inconsistencies and establishes a principled basis for the features we have > today as well as the enhancements we may need in the future. It does this > with minimal breaking changes. > > The draft is included below and can also be found here: > https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md > . > > I’m looking forward to everyone’s feedback. > > Matthew > > > A Consistent Foundation For Access Control: Scope-Bounded Capabilities > > - Proposal: SE-NNNN > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md> > - Authors: Matthew Johnson <https://github.com/anandabits> > - Review Manager: TBD > - Status: Awaiting review > > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#introduction> > Introduction > > This proposal introduces a consistent foundation for all access control in > Swift: scope-bounded capabilities. The existing access control features are > generalized with a single mechanism that unifies their semantics. This > unified mechanism eliminates the inessential complexity and inconsistency > of the current system while expanding its utility. > > Swift-evolution thread: Discussion thread topic for that proposal > <https://lists.swift.org/pipermail/swift-evolution/> > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#motivation> > Motivation > > The new access control features in Swift 3 have proven to be extremely > controversial. The most common refrain is that we need a more simple > system. In order to accomplish this we need to do more than tweak the > system we already have. We need to revisit the foundation of the system > itself. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#simple-made-easy>Simple > Made Easy > > Rich Hickey gave a fantastic talk called [Simple Made Easy])( > https://www.infoq.com/presentations/Simple-Made-Easy). In this talk Rich > explores the etymology and relationship of the words "simple", "complex", > and "easy". The meanings he explores are: > > - Complex: entangled, intertwined, interleaved, braided together > - Simple: one strand, single focus, disentangled > - Easy: familiar, nearby, readily at hand > > The central point Rich makes in this talk is that when a design entangles > two orthogonal concepts complexity is the result. He coins the term > "complect" to refer to this kind of inessential complexity. This complexity > can be removed by disentangling the concepts. Instead of "complecting" > independent concerns we can *compose* them. > > The result is a simpler system. It is simpler because independent concepts > can be considered and understood independently of each other. > > The composition of independent concerns also results in a more flexible > system. When orthogonal concepts are entangled it is more difficult to > extend the system to meet future needs. One concept cannot be extended > independently of the other. It is not possible to make independent > decisions about what should be orthogonal aspects of the design. > > Rich believes that the programming community is often too quick to reach > for an immediately "easy" solution. Unfortunately, the "easy" solution > often entangles concepts and are therefor actually complex. He suggests > that we *first*design a simple (i.e. disentangled) solution and then > layer ease of use and familiarity on top, thus the title "Simple Made Easy". > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#two-orthogonal-concepts>Two > orthogonal concepts > > The access control system in Swift 3 incorporates two orthogonal concepts: > availability and capability. Availability is what immediately comes to mind > when one thinks of access control: a symbol is either available or it is > not. Capability is more nuanced. It refers to what you can *do* with that > symbol. > > Each declaration supports a *basic* capability which is always available > when the symbol itself is available. Many declarations also offer > *additional* capabiities (such as the ability to inherit, override, set a > property, etc). These additional capabilities may be *less available* than > the symbol itself. > > In Swift, availability is always specified in terms of a scope. Swift does > not currently have a consistent way to talk about capabilities. Thus far we > have introduced new syntax every time we wish to distinguish the > availabiltiy of an *additional*capability from that of the symbol itself: > > - open vs public access modifiers classes and methods > - Access modifier parameterization for setter availability: > private(set) > - The @closed attribute which has been discussed as a way to specify > non-resilient enums in Swift 4* > > It is clear that we need to be able to talk about not just basic > availability, but also *capabilities*. It would be very nice if we had one > consistent > way to do this. This can be accomplished by composing the concepts of > availability and capability into the notion of a *scope-bounded > capability*. > > *@closed would lie outside the access control system proper. It is > included for the sake of completeness. It is also included to demonstrate > how the language currently lacks a clear and obvious way to specify new > capability bounds when they are arise. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#problems-with-swifts-access-control-system>Problems > with Swift's access control system > > Swift's current access control system can has several problems. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#inconsistency> > Inconsistency > > As noted above, the ways *additional* capabilities are bounded is > inconsistent. The semantics of public are also inconsistent. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#internal-default>Internal > default > > The Swift evolution community has adopted the principle that nothing > should be available outside a module without an explicit declaration of > intent by a library author. This is an excellent default which protects > library authors against making an error of omission that would require a > breaking change to correct. Unfortunately this principle has not been > consistently applied. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#public> > public > > In *most* cases public only provides access to the *basic* capability a > declaration offers. This is true by definition for declarations do not > offer *additional* capabilities but it is *also* true for classes (with > respect to inheritance) and class methods (with respect to overrides). > > However, there are three cases where public currently provides access to > *additional* capabilities: > > - public var allows access to the setter > - public enum allows exhaustive switch > - public protocol allows new conformances to be introduced > > It is not currently possible to declare resilient enums or closed > protocols but both have received significant discussion. Further, resilient > enums need to be supported before ABI stability is declared. A consistent > access control system would treat these as independent capabilities that > are not made available with a simple public declaration. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#private-and-fileprivate> > private and fileprivate > > The most heavily debated aspect of the changes to the access control > system in Swift 3 is without question the change in meaning of private to > be the current lexical scope and the renaming of the file-level scope to > fileprivate. This change was made with the idea that a lexically scoped > private would prove to be a good "soft default" for a less-than-module > availability bound. While many users appreciate the semantics of a > scope-based access modifier it has not proven to be a good "soft default" > and therefore does not deserve the name private. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#extensions> > Extensions > > In languages without extensions lexically scoped availability is > equivalent to type-based availability for members of a type. In such a > language it could make a reasonable default. Swift is not such a language. > > Using several extensions on the same type within the same file is an > extremely common Swift idiom. This idiom is not well supported by a "soft > default" of scope-based availability. The tension between a pervasive idiom > and the "soft default" leads to confusion about when scope-based a > availability is appropriate, and often an overuse of the feature. It also > leads to the need to use fileprivate much more frequently than is > desirable for such an awkward keyword. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#types-and-members>Types > and members > > A "soft default" should not have subtle behavior that has the potential to > confuse beginners. Most beginners would expect Foo and bar in the > following example to have the same visibility. This was true in Swift 2 but > it is not true in Swift 3. > > private struct Foo { > private var bar = 42 > } > > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#an-advanced-feature>An > advanced feature > > Lexically scoped availability has important uses such as preserving > invariants. All access to invariant-related state can be routed through > basis methods which access the state carefully without violating > invariants, even when that access happens in an extension in the same file. > We should not abandon this tool but it should not be the "soft default". It > is best reserved for specific use cases where the guarantee it offers is > important to correctess of the software. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#essential-and-inessential-complexity>Essential > and inessential complexity > > The inconsistencies noted above and a bad "soft default" of private are > all forms of *inessential* complexity. This makes Swift's access control > system more difficult to understand and use than it needs to be and causes > confusion. > > At the same time the *essential* complexity of capabilities that are > bounded independent of basic symbol availability is not explicitly > acknowledged and embraced. This also makes the access control system more > difficult to understand and use than it should be. Users are not taught to > think in terms of independently bounded capabilities. This is a concept > that *could* be learned once and applied generally if it was more visible > in the language. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#proposed-solution>Proposed > solution > > The proposed solution is to establish a semantic foundation for access > control that is *simple* in the sense of composing rather than > interleaving independent concerns. The solution is made *easy* by > defining familiar names in terms of this foundation while preserving the > semantics Swift users expect them to have. It is *consistent* in its use > of a single mechanism for bounding capabilities and its default of > internal for *all* capabilities. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#scope-bounded-capabilities>Scope-bounded > capabilities > > All access control is defined in terms of a parameterized access modifier > that allows the user to specify a capability and a scope that bounds that > capability. > > // The scope of the setter is the current file.scope(set, file) var foo = 42 > > Here I suggest a bit different API to make it very distinct on which capability gets which access. Instead of ',' use ':' scope(set: file) vat foo = 42 Each parameter has a default argument. The default argument for the > capability is simply the *basic* capability the declaration provides. For > a variable this is the getter, for a method it is the ability to call the > method, for a type it is the ability to use the type and so on. The default > argument for the scope is the current lexical scope. > > // The scope of the getter is the current lexical scope.// This is equivalent > to `private var foo = 42` in Swift 3.scope var foo = 42 > // The scope of the getter is the current file.scope(file) var bar = 42 > // The scope of the setter is the current lexical scope.scope(set) var baz = > 42 > > The scope of the basic capability implicitly bounds additional > capabilities: if basic use of a symbol is not available it is not possible > to anything with that symbol. This is similar to the existing rule that a > type implicitly bounds the availability of all symbols declared within its > scope: a public property of an internal type is not available outside the > module because the type itself is not available. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#aliases> > Aliases > > This modifier is simple (in the sense defined above), general and > powerful. However it is also unfamiliar, often slightly verbose, and offers > a very wide configuration space. Familiar aliases are provided as "soft > defaults" which are recommended for common use cases. > > These aliases introduce no additional semantics. Once a user understand > scopes, capabilities and how they compose to produce scope-bounded > capabilities the user also has the ability to understand *all* aliases we > introduce. Tools could even make the definition of the alias available to > remind the user of its underlying meaning (similarly to they way Xcode > allows a user to command-click to see a symbol definition). > > These aliases are defined in terms of the parameterized scope modifier: > > - private(capability) = scope(capability, file) > - internal(capability) = scope(capability, submodule) > - public(capability) = scope(capability, everywhere) > - open = scope(inherit, everywhere) > - open = scope(override, everywhere) > - final = scope(inherit, nowhere) > - final = scope(override, nowhere) > - total = scope(switch, everywhere) > > private reverts to the Swift 2 semantics. scope with no parameters has > semantics equivalent to that of private in Swift 3. > > internal is specified in terms of submodule and is equivalent to module scope > until submodules are introduced. It is specified this way to indicate the > intent of the author should submodules be added. > > total is a placholder subject to bikeshedding. total enum provides > semantics equivalent to public enum. public enum receives the semantics > of resilient enums. If a suitable shorthand is not identified the slightly > longer public(switch) enum can be used to specify an enum which supports > exhaustive switch outside the module. > > open, final and closed are overloaded based on the kind of declaration > they are applied to. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#scopes> > Scopes > > The hierarchy of scopes is as follows: > > - nowhere > - lexical > - TypeName > - extension > - file > - submodule > - SubmoduleName > - module > - everywhere > > The name of any ancestor type or submodule of a declaration, including the > immediately containing type or submodule, form the set of valid > user-defined scope references. > > Including nowhere allows us to define final in terms of this system. It > also allows us to model all properties and functions with the same set of > capabilities: the setter of a read only property is automatically bounded > to nowhere and the override capability of a function that is not a class > method is automatically bounded to nowhere. > > Allowing users to reference any ancestor scope introduces affords advanced > users a degree of control that is not possible in the current access > control system. If submodules are introduced into Swift this additional > control will be especially useful as a means to facilitate bounded > collaboration between peer submodules allowing them to communicate in ways > not available to the rest of the module. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#capabilities> > Capabilities > > The capabilities available depend on the kind of declaration an access > modifier is applied to. All declarations offer a *basic*capability that > is always available when the declaration itself is available. The basic > capability is specified by default when the scope modifier or a > parameterized alias is used without an explicit capability argument. Some > declarations also offer *additional* capabilities which may have an > independent bound applied to them. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#properties-and-subscripts>Properties > and subscripts > > - get (the basic capability) > - set (for readwrite properties only) > - override (for class properties only) > > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#functions-and-initializers>Functions > and initializers > > - call (the basic capability) > - override (for class methods only) > > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#types> > Types > > - use (the basic capability) > - inherit (for classes) > - switch (for enums) > > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#protocols> > Protocols > > - use (the basic capability) > - conform > > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#extensions-and-typealiases>Extensions > and typealiases > > - use (the basic capability) > > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#scalable-in-the-future>Scalable > in the future > > As the language grows the mechanism of scope-bounded capabilities can be > extended in an obvious way to meet the needs of future declarations and > capabilities. Users are only required to learn about the new declaration or > capability that was introduced. Their existing knowledge of the > scope-bounded capability access control system is immediately applicable. > > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#detailed-design>Detailed > design > <https://github.com/anandabits/swift-evolution/blob/scope-bounded-capabilities/proposals/NNNN-scope-bounded-capabilities.md#rules> > Rules > > The rules which make up the *essential* complexity in Swift's access > control system are: > > - The default scope for all capabilites a declaration offers is > module-wide (or submodule-wide in the future). > - The scope of a capability may be modified by an explicit access > modifier. > - The scope of an *additional* capability is implicitly bounded by the > scope of the *basic* capability. > - The scope of an *additional* capability may not be explicitly > specified as greater than that of the *basic* capability. > - If no scope is explicitly provided for the *basic* capability and an > *additional* capability is specified to be available outside the > (sub)module the *basic* capability is also given the same availability. > - The scope of a declaration (including all capabilities) may be > bounded by the declaration of ancestor. > - The scope of a declaration may not be greater than the scope of the > capabilities necessary to use that declaration: if you can't see a > parameter type you can't call the function. > > Most of these rules already exist in Swift's access control system. There > is one change and one addition: > > - The first rule changes > >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution