Just scanned it, but my first impression is: LOVE IT!

IMO this is the way to go.

Though some of the details will no doubt be improved. I will read it in more 
depth coming WE.

Regards,
Rien

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





> On 02 Mar 2017, at 20:58, Matthew Johnson via swift-evolution 
> <[email protected]> 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
>       • Authors: Matthew Johnson
>       • Review Manager: TBD
>       • Status: Awaiting review
> 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
> 
> 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.
> 
> 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 
> firstdesign a simple (i.e. disentangled) solution and then layer ease of use 
> and familiarity on top, thus the title "Simple Made Easy".
> 
> 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.
> 
> Problems with Swift's access control system
> 
> Swift's current access control system can has several problems.
> 
> Inconsistency
> 
> As noted above, the ways additional capabilities are bounded is inconsistent. 
> The semantics of public are also inconsistent. 
> 
> 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.
> 
> 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.
> 
> 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.
> 
> 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.
> 
> 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
> 
> }
> 
> 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.
> 
> 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.
> 
> 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.
> 
> 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
> 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.
> 
> 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.
> 
> 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.
> 
> 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.
> 
> Properties and subscripts
> 
>       • get (the basic capability)
>       • set (for readwrite properties only)
>       • override (for class properties only)
> Functions and initializers
> 
>       • call (the basic capability)
>       • override (for class methods only)
> Types
> 
>       • use (the basic capability)
>       • inherit (for classes)
>       • switch (for enums)
> Protocols
> 
>       • use (the basic capability)
>       • conform
> Extensions and typealiases
> 
>       • use (the basic capability)
> 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.
> 
> Detailed design
> 
> 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 the availability of the additional capability 
> of public readwrite properties, protocols and enums.
>       • The fifth rule affords shorthand for implicitly making the basic 
> capability public when an additional capability is also made public.
> Grammar
> 
> The changes to the access modifier grammar are as follows:
> 
> access-level-modifier → scope­ | scope­(­ capability-specifier ­)­ | scope­(­ 
> scope-specifier ­)­ | scope­( capability-specifier ­, scope-specifier ­)­
> access-level-modifier → private­ | private­(­ capability-specifier ­)­
> access-level-modifier → internal­ | internal­(­ capability-specifier ­)­
> access-level-modifier → public­ | public­(­ capability-specifier ­)­
> access-level-modifier → open­
> access-level-modifier → final
> access-level-modifier → total
> 
> scope-specifier → nowhere | extension | file | submodule | module | 
> everywhere | identifier
> capability-specifier → set | inherit | override | conform | switch
> 
> Playground
> 
> A Swift playground that includes a prototype of the basic scope-bounded 
> capability access modifier as well as the aliases is availabe here.
> 
> Future possibilities
> 
> Scope-bounded capabilities are able to express set-only properties and 
> override-only methods with a minor change to the rules of the system. These 
> features have been requested on the list in the past. In the case of 
> override-only methods there are known examples in Apple's frameworks. 
> Allowing support for these would add some complexity to the model and is not 
> essential to establishing a consistent basis for the existing access control 
> feature.
> 
> Source compatibility
> 
> This proposal will not cause any Swift 3 source to fail to compile but will 
> produce different behavior in three cases. In all cases a mechanical 
> migration is possible.
> 
> public var
> 
> This proposal removes the availability of the setter of a public var outside 
> the module, requiring public(set) var to expose the setter. This requires a 
> migration of existing code. We could ease this transition with a deprecation 
> warning in one release and then introduce the semantic change in the 
> following release.
> 
> public enum
> 
> This proposal removes the availability of exhaustive switch from public 
> enums. Non-resilient enums will need to be declared as a total enum (or the 
> equivalent keyword chose after bikeshedding) or public(switch) enum if we 
> choose not to introduce an alias for this semantic. As with public var, a 
> deprecation warning and deferred semantic change could be used to ease the 
> transition.
> 
> public protocol
> 
> This proposal requires protocols conformable outside the module to use the 
> open protocol alias rather than public protocol. Visible but not conformable 
> protocols are out of scope for Swift 4. This means that in Swift 4 open 
> protocoland public protocol could share the same semantics with a deprecation 
> warning on public protocol telling users to use open and that the semantics 
> of public protocol will be different in the future. We could remove support 
> for public protocol in a point release, reserving it until we introduce the 
> ability for a protocol to be visible but not conformable.
> 
> Effect on ABI stability
> 
> If this proposal impacts ABI stability it would be in the area of runtime 
> metadata or introspection. Input on this topic is welcome.
> 
> Effect on API resilience
> 
> This proposal does not impact API reslience. The proposed solution recasts 
> some existing features but does so in a way that should be backwards 
> compatible. No existing semantics are changed, only how those semantics are 
> stated syntactically.
> 
> Alternatives considered
> 
> The primary alternative is to continue using the ad-hoc approach to meeting 
> our access control needs. There have been many different ideas about how we 
> might be able to simplify the current system by removing or slightly tweaking 
> some of the existing features. The author believes this approach will not be 
> able to meet future needs well and will continue to be burdened by the 
> accumulation of inessential complexity. This situation will get worse, not 
> better, as new features are added to the language.
> _______________________________________________
> 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

Reply via email to