[swift-evolution] [Draft] Harmonize access modifiers for extensions

Nevin Brackett-Rozinsky nevin.brackettrozinsky at gmail.com
Mon Jul 18 11:44:11 CDT 2016


>
> Now if the struct’s visibility is changed, each extension member will be
> accessible up to the maximum availability of the type, the extension, and
> itself.


…I of course meant “minimum” here.

Nevin


On Mon, Jul 18, 2016 at 12:25 PM, Nevin Brackett-Rozinsky <
nevin.brackettrozinsky at gmail.com> wrote:

> My understanding is that “being able to change access levels by
> simply flipping a switch on the type itself” is a positive goal of Swift.
>
> Therefore, it emphatically *should* be allowed to set the default
> visibility for an extension the same as (or higher than!) the type it
> extends. For example, a private type can be given a private extension, so
> later making the type internal will preserve the privacy of the extension
> members.
>
> If any change is to be made in this area, it should simply be that “the
> default access level of extension members is `internal`”, which means
> public members of an extension must be explicitly marked public.
>
> The access modifier on an extension would serve as an upper bound on
> visibility for its members, so the default (implicit) modifier for
> extensions would be “public”. Members of a public extension would be
> implicitly internal, as noted above.
>
> The visibility of a type is an upper bound on its members’ visibility as
> well, so in a sense we would be making all access modifiers, including
> those on member declarations, act as upper bounds. This allows designs like
> the following:
>
> [internal] struct makePublicInTheFuture { ... }
> [public] extension makePublicInTheFuture {
>   private var _p
>   fileprivate var _f
>   [internal] var _i
>   public var x
>   ...
> }
>
> Now if the struct’s visibility is changed, each extension member will be
> accessible up to the maximum availability of the type, the extension, and
> itself.
>
> That seems like the most consistent approach to me.
>
> However, I am still not convinced that any change is required at all. The
> only “problem case” now is `public extension` making its member public by
> default. I am not a framework designer, so I do not know how useful or
> non-useful this may be.
>
> But if any change is to be made, I think “extension members default to
> internal” is the simplest.
>
> All access modifier act as upper bounds, extensions are implicitly
> `public`, and other declarations (including types) are implicitly
> `internal`.
>
> Then programmers can set access levels to “where they should be” in
> preparation for “flipping the switch” on a type or extension’s visibility
> in the future, and public APIs must be explicitly marked `public` at the
> declaration site.
>
> How does this sound?
>
> Nevin
>
>
>
>
> On Mon, Jul 18, 2016 at 11:32 AM, Xiaodi Wu via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> On Mon, Jul 18, 2016 at 6:09 AM, Adrian Zubarev via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>>> +1 :)
>>>
>>> Let’s analyze this: public > internal > fileprivate >= private
>>>
>>> An extension may optionally be marked with an explicit access modifier
>>> that specifies the default scope [see SE–0025]. However, such an explicit
>>> modifier *must not match* (or exceed) the original type’s access level.
>>>
>>> public struct A {}
>>>
>>> // I assume that we go with "must not match" here!
>>>
>>> // can't be public anymore -> no more
>>> // <<implicitly>> public extension members
>>> // -> breaking change -> I can live with that
>>> extension A {}
>>>
>>> // no default access modifier -> extension
>>> // follows the access rule by the extended type A
>>> // -> here every extension member is internal by default
>>> // -> can be overridden to public member wise
>>> extension A {}
>>>
>>> // default access modifier acts as the upper bound
>>> // inside an extended public type A
>>> // -> every extension member are fileprivate
>>> // -> extension member can be explicitly set to private
>>> // -> these will be only visible inside this extension scope
>>> fileprivate extension A {}
>>>
>>> // at file scope `private` acts like `fileprivate`
>>> // (if `private` is allowed at filescope) - haven't read the extended SE-0025 yet
>>> // -> I assume any member that are explicitly set to private
>>> // will only be visible inside this extension scope
>>> private extension A {}
>>>
>>> Let’s check internal types:
>>>
>>> internal struct B {}
>>>
>>> // "must not match" does not work here anymore
>>> // do we use "must not exceed" here???
>>>
>>> // I assume the second.
>>>
>>> // doens't break anything
>>> // works as before
>>> // no default access modifier for internal types
>>> // equals `internal extension A {}`
>>> // members are default internal
>>> // -> can be overridden to `fileprivate` or scope level `private`
>>> extension B {}
>>>
>>> // same as for `public extension A`
>>> fileprivate extension B {}
>>>
>>> // same as for `public extension A`
>>> private extension B {}
>>>
>>> // that sounds fine right?
>>>
>>> // let's check if we'd go with "must not match" instead:
>>>
>>> // we cannot extend internal types with internal members
>>> // anymore -> ups, that would be really strange
>>> extension B {}
>>>
>>>
>> Adrian, I propose only that _explicit_ access modifiers on extensions
>> must not match the access level of the original type. This proposal does
>> not touch what happens inside extensions without explicit access modifiers.
>> I had to re-read SE-0025 a few times to fully understand its meaning.
>> According to SE-0025, "extensions with explicit access modifiers continue
>> to override the default `internal` access." This implies that members
>> declared inside an extension without an explicit access modifier will have
>> default `internal` access. Likewise, "the compiler will continue to warn on
>> overly broad access within an extension with an explicit access modifier."
>> This implies that, in the absence of an explicit access modifier, the
>> compiler will not warn about overly broad access inside types, just as it
>> will not for members inside types.
>>
>>
>>> // same as for `public extension A`
>>> fileprivate extension B {}
>>>
>>> // same as for `public extension A`
>>> private extension B {}
>>>
>>> Just for the record we also check fileprivate and private:
>>>
>>> fileprivate struct C {}
>>>
>>> // "must not exceed" assumed
>>>
>>> // no default access modifier means all
>>> // extension member will folow the upper bound by
>>> // the extended type -> fileprivate by default
>>>
>>> (See discussion above.)
>>
>>>
>>> // -> members can be set to be `private` and only
>>> // visible inside this extension scope
>>> // -> equivalent to `fileprivate extension B {}`
>>> // and `private extension C {}`
>>> extension C {}
>>>
>>> // "must not match" -> would break like it breaks the
>>> // internal access model
>>>
>>>
>> See above. Nothing breaks.
>>
>>  ``swift // at file scope acts likefileprivate` private struct D {}
>>>
>>> // “must not exceed” assumed
>>>
>>> // same as for fileprivate extension D {}
>>>
>>> // “must not match” -> would break ```
>>>
>>> Great compromise here!
>>>
>>> This rule would preserve the possibility of using extensions as grouping
>>> constructs. At the same time, it would (1) remove the possibility of
>>> writing public extension to default the access level of members to public;
>>>
>>> We still can group internal and fileprivate with this, but it’s okay I
>>> guess.
>>>
>>> Let’s re-check default protocol implementation:
>>>
>>> public protocol G {
>>>     func foo()
>>> }
>>>
>>> // currently we have 3 different ways to make them public
>>> // #1
>>> extension G {
>>>     public func foo() { /* implement */ }
>>> }
>>>
>>> // #2
>>> public extension G {
>>>     func foo() { /* implement */ }
>>> }
>>>
>>> // #3
>>> public extension G {
>>>     public func foo() { /* implement */ }
>>> }
>>>
>>> // with "must not match" for `public` only #1 will work
>>> // but everyone will need to repeat `public`
>>> // no laziness for `public` anymore - hurray
>>> extension G {
>>>     public func foo() { /* implement */ }
>>> }
>>>
>>> // "must not exceed" doesn't solve the problem of `public` at all
>>>
>>> The last topic is conformance to protocols:
>>>
>>> public protocol P {}
>>> internal protocol PI {}
>>> fileprivate protocol PF {}
>>> private protocol PP {}
>>>
>>> public type Y {}
>>>
>>> // "must not exceed" results in this, which is what it looks right now
>>> extension Y : P {}
>>>
>>> // just fine here
>>> // we still can grant `PI` members visibility up to `public`
>>> // the lower bound for these is `internal`
>>> extension Y : PI {}
>>>
>>> // same as `PI` but the lower bound is `fileprivate` now
>>> extension Y : PF {}
>>>
>>> // same as `PI` but the lower bound is `private` now
>>> extension Y : PP {}
>>>
>>> // this does not work atm.
>>> // but should be allowed in general where we could grant visibility up to `internal`
>>> internal extension Y : PI, PF, PP {}
>>>
>>> fileprivate extension Y : PF, PP {}
>>>
>>> There are a few more combinations I don’t want to type out here.
>>>
>>>
>> As I mentioned previously, since explicit access modifiers are not
>> currently permitted for conformance to protocols, any such change is
>> additive and I do not include it within the scope of this proposal.
>>
>>
>>> My conclusion it this:
>>>
>>>    -
>>>
>>>    “must not match” does solve a few problems with public but only
>>>    allows explicit internal, fileprivate and private usage, which is
>>>    kinda odd. This is a new exceptional rule that must be documented.
>>>    -
>>>
>>>    “must not exceed” does not solve anything if it does not follow the
>>>    typical public with default internal rule.
>>>    1. With this exception it’s no more a default access modifier and
>>>       totally useless on extensions, except if >>no access modifier<< would mean
>>>       the upper bound is implicitly internal where you can’t grant
>>>       visibility up to public and forced to use public extension if you
>>>       wish to achieve this.
>>>       2. With the exception in (1) we would need to allow access
>>>       modifier on extension with protocol conformance to achieve the same result
>>>       everywhere.
>>>       3. With all that we’ll have to use #3 for default protocol
>>>       implementations to make them public.
>>>
>>> That said we’re end up with the same upper- lower bound access control
>>> model on extension I proposed, even if my proposal title and some of my
>>> writing there caused a lot of confusion.
>>>
>>>
>>>
>>> --
>>> Adrian Zubarev
>>> Sent with Airmail
>>>
>>> Am 18. Juli 2016 um 11:14:09, David Hart (david at hartbit.com) schrieb:
>>>
>>> This compromise solution looks very good to me. Thanks Xiaodi for the
>>> effort put into working through our whining to come to the best solution
>>> IMHO.
>>>
>>> On 18 Jul 2016, at 09:50, Xiaodi Wu via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> All righty, thanks for all of your feedback. I've worked on revising the
>>> proposal this evening, re-reading previous documents and messages and
>>> re-analyzing what people meant. I think Jose is absolutely right in the
>>> end, and the proposal has turned out like he suggested. Here is the current
>>> draft below:
>>>
>>> Harmonize access modifiers for extensions
>>>
>>>    - Proposal: SE-XXXX
>>>    <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md>
>>>    - Author: Xiaodi Wu <https://github.com/xwu>
>>>    - Status: Awaiting review
>>>    - Review manager: TBD
>>>
>>>
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md#introduction>
>>> Introduction
>>>
>>> During discussion of SE-0119
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/0119-extensions-access-modifiers.md>,
>>> some voiced concern that writing public extension increases the default
>>> access level for members declared within that extension, whereas writing public
>>> class or public struct does not do the same.
>>>
>>> This behavior is explained as follows: since extensions have no runtime
>>> representation and are not first-class entities, access modifiers on
>>> extensions serve as a shorthand to set the default access level for
>>> members. Certain members of the community have indicated that such behavior
>>> makes extensions a natural grouping construct.
>>>
>>> A general principle of Swift, recently strengthened by proposals such as
>>> SE-0117
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/0117-non-public-subclassable-by-default.md>,
>>> has been that public API commitments should require explicit opt-in. Given
>>> the different behavior of classes and structs, the fact that extensions
>>> allow public methods to be declared without spelling out public at the
>>> declaration site has been called "confusing" or "odd."
>>>
>>> The aim of this proposal is to, in as conservative a manner as possible,
>>> require explicit use of public for public methods declared inside any
>>> extension.
>>>
>>> Swift-evolution threads:
>>>
>>>    - [Proposal] Revising access modifiers on extensions
>>>    <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160620/022144.html>
>>>    - [Review] SE-0119: Remove access modifiers from extensions
>>>    <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160711/024224.html>
>>>    - [Draft] Harmonize access modifiers for extensions
>>>    <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160711/024522.html>
>>>
>>>
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md#motivation>
>>> Motivation
>>>
>>> Consider the following:
>>>
>>> public struct foo {
>>>   func frobnicate() { } // internal
>>> }
>>> public extension foo { }
>>>
>>> public struct bar { }
>>> public extension bar {
>>>   func frobnicate() { } // public
>>> }
>>>
>>> This outcome is explained by rules regarding access modifiers
>>> specifically on extensions Swift 2
>>> <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html>,
>>> which is slated for preservation in Swift 3 as detailed in SE-0025
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/0025-scoped-access-level.md>.
>>> However, it is arguably surprising that, of two declarations spelled
>>> identically, one leads to a public API commitment while the other does not.
>>>
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md#proposed-solution>Proposed
>>> solution
>>>
>>> The proposed solution is to amend access modifier rules to eliminate the
>>> possibility of defaulting the access level of members declared inside an
>>> extension to public.
>>>
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md#detailed-design>Detailed
>>> design
>>>
>>> Amend access modifier rules as follows:
>>>
>>> An extension may optionally be marked with an explicit access modifier
>>> that specifies the default scope [see SE-0025]. However, such an explicit
>>> modifier *must not match (or exceed) the original type's access level*.
>>>
>>> This rule would preserve the possibility of using extensions as grouping
>>> constructs. At the same time, it would (1) remove the possibility of
>>> writing public extension to default the access level of members to
>>> public; and (2) clarify the notion that an access modifier on an
>>> extension is a shorthand and not a way to create a first-class entity by
>>> disallowing repeating of the original type's access level.
>>>
>>> *Explicit* access modifiers will continue to set the maximum allowed
>>> access within an extension, as clarified in SE-0025.
>>>
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md#alternatives-considered>Alternatives
>>> considered
>>>
>>> One alternative is to eliminate explicit access modifiers on extensions
>>> altogether. As an advantage, this would further clarify the mental model
>>> that extensions are not their own first-class entities. As a disadvantage,
>>> extensions cease to be an access modifier grouping construct, which some
>>> users really like.
>>>
>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md#acknowledgments>
>>> Acknowledgments
>>>
>>> Thanks to all discussants on the list, especially Adrian Zubarev, Jose
>>> Cheyo Jimenez, and Paul Cantrell.
>>>
>>>
>>> On Sun, Jul 17, 2016 at 11:08 AM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>
>>>> I understand how it works.
>>>>
>>>> By aligning access modifier rules inside extensions with those inside
>>>> types, all other modifiers would continue to work as it does now
>>>> (implicitly internal members would be limited by the upper bound). The only
>>>> change in this respect is removing the ability to have public API without
>>>> writing `public func`.
>>>>
>>>> On Sun, Jul 17, 2016 at 11:01 Adrian Zubarev via swift-evolution <
>>>> swift-evolution at swift.org> wrote:
>>>>
>>>>> I tackled it as an upper bound but highly rejected by the community.
>>>>> That’s exactly what my proposal was all about. An upper boundary would be
>>>>> more elegant, but I still see arguments ‘because it’s not a type’.
>>>>>
>>>>> I could live without access modifiers on extensions in general.
>>>>>
>>>>> The default access modifier rule permits public methods to be written
>>>>> without public func
>>>>>
>>>>> You meant this?
>>>>>
>>>>> public extension SomeType {
>>>>>     // I don't need to write public
>>>>>     func foo() {}
>>>>>     var computed: Type {}
>>>>> }
>>>>>
>>>>> This applies to all access modifiers which are not optional (like
>>>>> internal):
>>>>>
>>>>> public SomeType
>>>>> fileprivate extension SomeType {
>>>>>     // I don't need to repeat fileprivate
>>>>>     func foo() {}
>>>>>     var computed: Type {}
>>>>> }
>>>>>
>>>>> // which is more likely `fileprivate` because it's on file scope
>>>>> private extension SomeType {
>>>>>     // even if the inner access modifier would pretend to be private
>>>>>     // since the extension is on filescope, everything will be `fileprivate`
>>>>>     func foo() {}
>>>>>     var computed: Type {}
>>>>> }
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Adrian Zubarev
>>>>> Sent with Airmail
>>>>>
>>>>> Am 17. Juli 2016 um 17:50:31, Xiaodi Wu (xiaodi.wu at gmail.com) schrieb:
>>>>>
>>>>> The proposal is that the access modifier for an extension will either
>>>>> be removed entirely or remain as an upper bound, losing its function as a
>>>>> default access modifier. The default access modifier rule permits public
>>>>> methods to be written without `public func`; this is a proposal to remove
>>>>> that feature because it is a source of confusion.
>>>>> On Sun, Jul 17, 2016 at 10:43 Adrian Zubarev via swift-evolution <
>>>>> swift-evolution at swift.org> wrote:
>>>>>
>>>>>> I still don’t catch to point here. There is no implicit public
>>>>>> there. It’s explicit set by the default access modifier of extensions. It’s
>>>>>> how they work and how they should remain (at least as long the community
>>>>>> want default access modifier to exist on extensions). Disallowing
>>>>>> setting public on extensions when you extend a public type makes no
>>>>>> sense. If you want your member to be internal like it’s in types,
>>>>>> then remove the access modifier from extension and all member will follow
>>>>>> the type access modifier.
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Adrian Zubarev
>>>>>> Sent with Airmail
>>>>>>
>>>>>> Am 17. Juli 2016 um 17:37:02, Xiaodi Wu (xiaodi.wu at gmail.com)
>>>>>> schrieb:
>>>>>>
>>>>>> That's a good point. I will incorporate these into a revised draft.
>>>>>> Only two things will change:
>>>>>>
>>>>>> ```
>>>>>> public struct Foo {
>>>>>>   // implicitly internal
>>>>>>   func frobnicate1() { }
>>>>>> }
>>>>>> public extension Foo {
>>>>>>   // currently implicitly public
>>>>>>   //
>>>>>>   // depending on which alternative is adopted,
>>>>>>   // the proposal will either prohibit `public extension`
>>>>>>   // or this method will be implicitly internal
>>>>>>   func frobnicate2() { }
>>>>>> }
>>>>>> ```
>>>>>>
>>>>>> ```
>>>>>> internal struct Bar {
>>>>>>   // permitted by SE-0025 without a warning
>>>>>>   // this method can only be accessed within module anyway
>>>>>>   // because `internal struct` bounds access of its members
>>>>>>   public func frobnicate1() { }
>>>>>> }
>>>>>> extension Bar {
>>>>>>   // not permitted by SE-0025
>>>>>>   //
>>>>>>   // after proposal, this will also be permitted without a warning
>>>>>>   // and this method will also be accessible only within module
>>>>>>   public func frobnicate2() { }
>>>>>> }
>>>>>> ```
>>>>>>
>>>>>> On Sun, Jul 17, 2016 at 1:50 AM, Adrian Zubarev via swift-evolution <
>>>>>> swift-evolution at swift.org> wrote:
>>>>>>
>>>>>>> I’m struggling to understand your proposal, can you provide some
>>>>>>> specific code samples how it works now and what will change. The example
>>>>>>> from the draft doesn’t help my understanding. :/
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Adrian Zubarev
>>>>>>> Sent with Airmail
>>>>>>>
>>>>>>> Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (
>>>>>>> swift-evolution at swift.org) schrieb:
>>>>>>>
>>>>>>> On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <
>>>>>>> cheyo at masters3d.com> wrote:
>>>>>>>
>>>>>>>> I think you can simplify this proposal by just saying something
>>>>>>>> like this and give a couple of examples that are easy to follow:
>>>>>>>>
>>>>>>>> Disallow explicit public access modifier on non-protocol-conforming
>>>>>>>> type extensions.
>>>>>>>>
>>>>>>>
>>>>>>> It took me a while to process what you're trying to say here, but
>>>>>>> this is a good idea and would go along well with the first draft's proposed
>>>>>>> solution. I will spell it out. (If we say that you can use an explicit
>>>>>>> modifier only to lower the access level of members, then `public` as an
>>>>>>> explicit modifier could be entirely disallowed.)
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> I think if you only focus on that breaking change then the proposal
>>>>>>>> will have a good chance of getting accepted and fixing the immediate issue
>>>>>>>> of public. There is a reason why protocol conforming extensions do not
>>>>>>>> allow explicitly saying public
>>>>>>>> `public extension Type: Protocol {}` // public not allowed
>>>>>>>>
>>>>>>>
>>>>>>> Actually, no modifiers are allowed in that scenario, IIUC.
>>>>>>>
>>>>>>>>
>>>>>>>> In essence we will be asking for the same behavior for types.
>>>>>>>>
>>>>>>>> Allowing methods declared inside extensions to have a higher
>>>>>>>> declared visibility is not a breaking change and can be introduced later.
>>>>>>>>
>>>>>>>
>>>>>>> It is a breaking change in that I am proposing that the rules be
>>>>>>> harmonized so that the implicit default access level will be notionally
>>>>>>> `internal` (there are follow-on benefits to this change). That cannot be
>>>>>>> changed later.
>>>>>>>
>>>>>>>
>>>>>>>> Nobody wants private extensions or implicit internal extensions to
>>>>>>>> go away. :)
>>>>>>>>
>>>>>>>
>>>>>>> I know that there are people who don't want it to go away. That was
>>>>>>> why the first draft proposed keeping them, but it sounds like it would make
>>>>>>> for an illogical system. I know that Jordan and John have both indicated
>>>>>>> that they don't think it's worth keeping around but don't seem to feel too
>>>>>>> strongly about it, and I think I feel the same way (leaning towards not
>>>>>>> keeping them, but don't feel very strongly). I will definitely feature this
>>>>>>> concern (using extensions as access modifier groups) prominently in the
>>>>>>> proposal and hope for a robust discussion to see how it plays out with the
>>>>>>> community and core team.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> On Jul 16, 2016, at 4:22 PM, Xiaodi Wu via swift-evolution <
>>>>>>>> swift-evolution at swift.org> wrote:
>>>>>>>>
>>>>>>>> On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david at hartbit.com>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> This proposal really confuses me. Two comments:
>>>>>>>>>
>>>>>>>>> 1) With the proposal, we loose the ability to use access modifiers
>>>>>>>>> on extensions as a way of grouping members by access. That's a huge loss
>>>>>>>>> for me.
>>>>>>>>>
>>>>>>>>
>>>>>>>> You lose the ability to group public members only. That part is
>>>>>>>> intentional, so that only methods declared with `public func` are public.
>>>>>>>>
>>>>>>>>
>>>>>>>>> 2) If we adopt the proposal, I now have no idea what explicit
>>>>>>>>> access modifiers on extensions do.
>>>>>>>>>
>>>>>>>>
>>>>>>>> I propose keeping explicit access modifiers because previous
>>>>>>>> comments on this list have said that it's useful for grouping members by
>>>>>>>> access. You can continue to use extensions to group fileprivate members of
>>>>>>>> an internal type, or internal members of a public type.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> More generally, I don't understand this proposal as it's trying to
>>>>>>>>> apply the same access modifier rules on extensions as for types but
>>>>>>>>> extensions are not types. They are just a declaration for extending types
>>>>>>>>> which already have an access level.
>>>>>>>>>
>>>>>>>>> On 16 Jul 2016, at 20:04, Xiaodi Wu via swift-evolution <
>>>>>>>>> swift-evolution at swift.org> wrote:
>>>>>>>>>
>>>>>>>>> With the impending withdrawal of SE-0119 and the closing window
>>>>>>>>> for (most) source-breaking changes, I thought I'd draft up a proposal to
>>>>>>>>> address some of the key points raised in that discussion.
>>>>>>>>>
>>>>>>>>> The proposed changes are deliberately limited in scope to
>>>>>>>>> rationalizing access modifier rules without adding any new facilities (such
>>>>>>>>> as conformances of lower visibility than the type), which might be more
>>>>>>>>> appropriate for the Swift 4 timeline.
>>>>>>>>>
>>>>>>>>> I hope this will prove satisfactory to the community :)
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Harmonize access modifiers for extensions
>>>>>>>>>
>>>>>>>>>    - Proposal: SE-XXXX
>>>>>>>>>    <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/XXXX-harmonize-access-modifiers.md>
>>>>>>>>>    - Author: Xiaodi Wu <https://github.com/xwu>
>>>>>>>>>    - Status: Awaiting review
>>>>>>>>>    - Review manager: TBD
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> <https://github.com/xwu/swift-evolution/tree/harmonize-access-modifiers#introduction>
>>>>>>>>> Introduction
>>>>>>>>>
>>>>>>>>> During discussion of SE-0119
>>>>>>>>> <https://github.com/xwu/swift-evolution/blob/harmonize-access-modifiers/proposals/0119-extensions-access-modifiers>,
>>>>>>>>> the community articulated the view that access modifiers for extensions
>>>>>>>>> were and should continue to be subject to the same rules as access
>>>>>>>>> modifiers for types. Unfortunately, it is not factually true today; this
>>>>>>>>> proposal aims to make it so.
>>>>>>>>>
>>>>>>>>> Swift-evolution threads:
>>>>>>>>>
>>>>>>>>>    - [Proposal] Revising access modifiers on extensions
>>>>>>>>>    <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160620/022144.html>
>>>>>>>>>    - [More to be added here]
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> <https://github.com/xwu/swift-evolution/tree/harmonize-access-modifiers#motivation>
>>>>>>>>> Motivation
>>>>>>>>>
>>>>>>>>> Consider the following:
>>>>>>>>>
>>>>>>>>> public struct foo {
>>>>>>>>>   func frobnicate() { } // implicitly internal
>>>>>>>>> }
>>>>>>>>> public extension foo { }
>>>>>>>>>
>>>>>>>>> public struct bar { }
>>>>>>>>> public extension bar {
>>>>>>>>>   func frobnicate() { } // implicitly public, according to SE-0025
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> According to SE-0025, a method moved from the body of a public
>>>>>>>>> struct into a public extension becomes public without modification. This is
>>>>>>>>> surprising behavior contrary to Swift's general rule of not exposing public
>>>>>>>>> API by default.
>>>>>>>>>
>>>>>>>>> Furthermore, SE-0025 now permits the owner of a type to design
>>>>>>>>> access for members as though the type will have a higher access level than
>>>>>>>>> it currently does. For example, users will be able to design
>>>>>>>>> public methods inside an internaltype before "flipping the
>>>>>>>>> switch" and making that type public. The same approach is
>>>>>>>>> prohibited by SE-0025 for extensions, although conceptually it need not be.
>>>>>>>>>
>>>>>>>>> <https://github.com/xwu/swift-evolution/tree/harmonize-access-modifiers#proposed-solution>Proposed
>>>>>>>>> solution
>>>>>>>>>
>>>>>>>>> The proposed solution is to change access modifier rules for
>>>>>>>>> extensions with the following effect: if any method (or computed property)
>>>>>>>>> declared within the body of a type at file scope is moved without
>>>>>>>>> modification into the body of an extension in the same file, the move will
>>>>>>>>> not change its accessibility.
>>>>>>>>>
>>>>>>>>> In code:
>>>>>>>>>
>>>>>>>>> struct foo {
>>>>>>>>>   // Any method declared here...
>>>>>>>>> }
>>>>>>>>> extension foo {
>>>>>>>>>   // ...should have the same visibility when moved here.
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> This implies that public API commitments will need to be annotated
>>>>>>>>> as public at declaration sites inside an extension just as it
>>>>>>>>> must be at declaration sites inside types.
>>>>>>>>>
>>>>>>>>> <https://github.com/xwu/swift-evolution/tree/harmonize-access-modifiers#detailed-design>Detailed
>>>>>>>>> design
>>>>>>>>>
>>>>>>>>>    1. Declarations inside the extension will, like declarations
>>>>>>>>>    inside types, have a default access level of internal.
>>>>>>>>>    2. The compiler should not warn when a broader level of access
>>>>>>>>>    control is used for a method (or computed property, etc.) declared within
>>>>>>>>>    an extension with more restrictive access. This allows the owner of the
>>>>>>>>>    extension to design the access level they would use for a method if the
>>>>>>>>>    type or extension were to be made more widely accessible.
>>>>>>>>>    3. An extension declared without an explicit access modifier
>>>>>>>>>    will have the same access level as the type being extended.
>>>>>>>>>    4. An extension declared without protocol conformance may
>>>>>>>>>    optionally use an explicit access modifier to provide an upper bound for
>>>>>>>>>    the visibility of its members.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> <https://github.com/xwu/swift-evolution/tree/harmonize-access-modifiers#alternatives-considered>Alternatives
>>>>>>>>> considered
>>>>>>>>>
>>>>>>>>>    - One alternative, still open for consideration, is to
>>>>>>>>>    eliminate #4 and disallow explicit access modifiers on extensions. As an
>>>>>>>>>    advantage, this would clarify the mental model that extensions are not
>>>>>>>>>    their own entities, as they cannot be referred to by name and have no
>>>>>>>>>    runtime representation. As a disadvantage, extensions cease to be an access
>>>>>>>>>    modifier grouping construct, which some users really like.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> <https://github.com/xwu/swift-evolution/tree/harmonize-access-modifiers#acknowledgments>
>>>>>>>>> Acknowledgments
>>>>>>>>>
>>>>>>>>> Thanks to all discussants on the list, especially Adrian Zubarev
>>>>>>>>> and Jose Cheyo Jimenez.
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> swift-evolution mailing list
>>>>>>>>> swift-evolution at swift.org
>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>>
>>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> swift-evolution mailing list
>>>>>>>> swift-evolution at swift.org
>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>
>>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution at swift.org
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution at swift.org
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>
>>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> swift-evolution at swift.org
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution at swift.org
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>
>>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160718/c5873643/attachment.html>


More information about the swift-evolution mailing list