[swift-evolution] [Draft] Harmonize access modifiers for extensions
Xiaodi Wu
xiaodi.wu at gmail.com
Mon Jul 18 13:41:26 CDT 2016
On Mon, Jul 18, 2016 at 1:24 PM, Nevin Brackett-Rozinsky <
nevin.brackettrozinsky at gmail.com> wrote:
> I remember it differently. The opposition to SE-0119 “Remove access
> modifiers from extensions” was primarily because the proposal itself was
> malformed and, to quote you from the review thread, “doesn’t do what it
> says on the tin (aka in the title)”.
>
> In that thread Jordan Rose said “the proposal is unclear” and he
> personally is against making “access modifiers on extensions set a maximum
> level of access for members, like they do for types” because he doesn’t
> think “people should think of extensions as first-class entities.”
>
> However, the core team as a whole never weighed in on the matter, and
> Chris Lattner included “Revising access modifiers on extensions” in the
> list of “open Swift 3 design topics”.
>
> If we had a proposal titled “Make all access modifiers act as upper
> bounds” which explained that (since the follow-on of SE-0025) they already
> behave this way on both types and members, and all that remains is to bring
> the same behavior to extensions, I think it would gain substantial traction.
>
> Notably, this approach does not involve thinking of extensions as
> “first-class entities”, but simply as a grouping and extending mechanism.
>
> The benefits include consistency and simplicity of the model, as well as
> ensuring that public APIs must be marked `public` at the declaration site,
> while still allowing “private extension” to work as expected.
>
> If you and I both agree that this is the sensible approach, and it has
> never actually been reviewed on its merits, and it addresses an open Swift
> 3 design topic, then I think we should push it forward.
>
> So far the only opposition that has been voiced to this approach was a
> claim that it encouraged “thinking of extensions as first-class entities”.
> I disagree with that assessment, and I do not think we should let such an
> opinion preemptively derail the cogent and straightforward answer.
>
Sure; with the PR already in the queue, let's bring this up during review
(assuming there will be one). I, for one, think it is a cogent argument.
>
> All that said, I am still not convinced there is anything wrong with the
> way things work now.
>
> Nevin
>
>
> On Mon, Jul 18, 2016 at 12:45 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
>> On Mon, Jul 18, 2016 at 11:25 AM, 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.
>>>
>>
>> I agree.
>>
>> 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.
>>>
>>
>> As discussed in SE-0119, there is no such thing as a private extension as
>> a first-class entity. The default access modifier is *only* modifying the
>> members declared within; therefore, using the "flipping a switch" analogy,
>> it is not a switch but rather the default lightbulb; the only relevant
>> switch is the access modifier of the original type.
>>
>> 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.
>>>
>>
>> That requires no change, as it is already slated to be the rule after
>> SE-0025.
>>
>>
>>> The access modifier on an extension would serve as an upper bound on
>>> visibility for its members,
>>>
>>
>> That approach was my first instinct as well, but it was rejected in
>> SE-0119.
>>
>>
>>> 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.
>>>
>>
>> It took me a while to understand what Jordan and John were saying in the
>> review process for SE-0119, but I think I now understand. They and others
>> reject the upper bound approach because, unlike types, extensions are not
>> first-class entities. Therefore, because they do not exist, extensions
>> should not be able to set bounds.
>>
>>
>>> 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.
>>>
>>
>> If you look back, that was indeed my first draft of this proposal.
>> However, feedback has made it clear that only two options are potentially
>> acceptable: access modifiers on extensions can either be eliminated, or
>> they can continue to be a shorthand, but they cannot be harmonized to be
>> upper bounds.
>>
>>
>>> 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?
>>>
>>
>> It sounded great to me, but it was shot down in SE-0119 and it was
>> rejected again on the first draft of this proposal.
>>
>>
>>>
>>> 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/6373d74d/attachment.html>
More information about the swift-evolution
mailing list