> On Mar 3, 2017, at 11:26 AM, BJ Homer <bjho...@gmail.com> wrote:
> 
> I agree that “scope(set: file)” reads better. It does make it a little 
> strange that “scope(set)" is also valid, though; it’s ambiguous whether it 
> takes labeled or unlabeled arguments. Under this proposal, all of these are 
> valid:
> 
> scope var                     == scope(get, lexical)
> scope(set) var                        == scope(set, lexical)
> private(set) var              == scope(set, file)
> internal(set) var             == scope(set, submodule)
> public(set) var                       == scope(set, everywhere)
> 
> For beginner users, the use of “scope” as both an access modifier and a 
> capability modifier seems a bit confusing; we’re “complecting” access control 
> and capability control. Perhaps we should avoid the concept of “default 
> arguments” altogether by separating the “scope” access control keyword from 
> the concept of capability control. What about something like this?
> 
> scoped var                    == access(get: lexical)
> scoped(set) var               == access(set: lexical)
> private(set) var              == access(set: file)
> internal(set) var             == access(set: submodule)
> public(set) var                       == access(set: everywhere)
> 
> Under this proposal, “scoped” is just another alias, similar to “private", 
> “internal", and “public”. It does not have a privileged position, and it’s 
> written as an adjective just like the others. The downside here is that we’re 
> introducing two new keywords instead of one, but it means that we don’t need 
> to mentally insert any default arguments. (The name of “access” is a 
> placeholder, subject to bikeshedding.)

I’m definitely going to change the proposal to use `scoped` and `access`.  
Expressing the capability using an argument label is an interesting approach.  
The problem is that it stretches the way the aliases are defined pretty far.  
You can’t take an argument and use it as an argument *label* in a function you 
call.  It also requires the model to have one overload for each capability 
instead of a single generic function.

One of the big ideas here is that access modifiers can be conceptualized as an 
expression of a generic type BoundedCapability that is specialized according to 
the context of the declaration it is applied to.  I don’t think we’d ever want 
to go in this direction, but it is theoretically possible that this could 
become a real expression that is evaluated at compile-time.

> 
> -BJ
> 
> 
> 
>> On Mar 3, 2017, at 4:23 AM, Daniel Leping via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 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 <mailto: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
>>  
>> <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 
>> <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 
>> firstdesign 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 additionalcapability 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 basiccapability 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 <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>

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

Reply via email to