[Draft] Harmonize access modifiers for extensions


(Xiaodi Wu) #1

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 :slight_smile:

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.


(Xiaodi Wu) #2

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.

···

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@hartbit.com> wrote:

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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Adrian Zubarev) #3

Have you by any chance meant this?

You can extend a class, structure, or enumeration in any access context in which the class, structure, or enumeration is available. Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add will have a default access level of internal. If you extend a private type, any new type members you add will have a default access level of private.

[HERE]: Alternatively, you can mark an extension with an explicit access level modifier (for example, private extension) to set a new default access level for all members defined within the extension.

This new default can still be overridden within the extension for individual type members.

Source
This is not according SE–0025 to me. It’s how access control on extensions worked all the time (which I misunderstood when posting my first draft).

···

--
Adrian Zubarev
Sent with Airmail

Am 16. Juli 2016 um 20:04:38, Xiaodi Wu via swift-evolution (swift-evolution@swift.org) schrieb:

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.


(Xiaodi Wu) #4

Have you by any chance meant this?

You can extend a class, structure, or enumeration in any access context in
which the class, structure, or enumeration is available. Any type members
added in an extension have the same default access level as type members
declared in the original type being extended. If you extend a public or
internal type, any new type members you add will have a default access
level of internal. If you extend a private type, any new type members you
add will have a default access level of private.

[HERE]: *Alternatively, you can mark an extension with an explicit access
level modifier (for example, private extension) to set a new default access
level for all members defined within the extension.*

This new default can still be overridden within the extension for
individual type members.

Source
<https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html>

This is not according SE–0025 to me. It’s how access control on extensions
worked all the time (which I misunderstood when posting my first draft).

Ah right; it is how it's always worked. I will amend the Motivation section
to say that.

Am 16. Juli 2016 um 20:04:38, Xiaodi Wu via swift-evolution (

···

On Sat, Jul 16, 2016 at 1:13 PM, Adrian Zubarev via swift-evolution < swift-evolution@swift.org> wrote:

swift-evolution@swift.org) schrieb:

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.

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


(Chéyo Jiménez) #5

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.

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

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.

Nobody wants private extensions or implicit internal extensions to go away. :slight_smile:

···

On Jul 16, 2016, at 4:22 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

Harmonize access modifiers for extensions

Proposal: SE-XXXX
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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
[More to be added here]
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.

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.

Detailed design

Declarations inside the extension will, like declarations inside types, have a default access level of internal.
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.
An extension declared without an explicit access modifier will have the same access level as the type being extended.
An extension declared without protocol conformance may optionally use an explicit access modifier to provide an upper bound for the visibility of its members.
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.
Acknowledgments

Thanks to all discussants on the list, especially Adrian Zubarev and Jose Cheyo Jimenez.

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

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


(Xiaodi Wu) #6

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. :slight_smile:

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 Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@masters3d.com> wrote:

On Jul 16, 2016, at 4:22 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Adrian Zubarev) #7

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. :confused:

···

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

Harmonize access modifiers for extensions

Proposal: SE-XXXX
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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
[More to be added here]
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.

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.

Detailed design

Declarations inside the extension will, like declarations inside types, have a default access level of internal.
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.
An extension declared without an explicit access modifier will have the same access level as the type being extended.
An extension declared without protocol conformance may optionally use an explicit access modifier to provide an upper bound for the visibility of its members.
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.
Acknowledgments

Thanks to all discussants on the list, especially Adrian Zubarev and Jose Cheyo Jimenez.

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

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

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


(Xiaodi Wu) #8

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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (
swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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


(Adrian Zubarev) #9

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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

Harmonize access modifiers for extensions

Proposal: SE-XXXX
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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
[More to be added here]
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.

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.

Detailed design

Declarations inside the extension will, like declarations inside types, have a default access level of internal.
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.
An extension declared without an explicit access modifier will have the same access level as the type being extended.
An extension declared without protocol conformance may optionally use an explicit access modifier to provide an upper bound for the visibility of its members.
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.
Acknowledgments

Thanks to all discussants on the list, especially Adrian Zubarev and Jose Cheyo Jimenez.

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

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

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

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


(Xiaodi Wu) #10

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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (
swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

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


(Adrian Zubarev) #11

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@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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

Harmonize access modifiers for extensions

Proposal: SE-XXXX
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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
[More to be added here]
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.

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.

Detailed design

Declarations inside the extension will, like declarations inside types, have a default access level of internal.
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.
An extension declared without an explicit access modifier will have the same access level as the type being extended.
An extension declared without protocol conformance may optionally use an explicit access modifier to provide an upper bound for the visibility of its members.
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.
Acknowledgments

Thanks to all discussants on the list, especially Adrian Zubarev and Jose Cheyo Jimenez.

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

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

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

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

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


(Xiaodi Wu) #12

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@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@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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (
swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

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

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


(Xiaodi Wu) #13

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@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@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@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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (
swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez < >>>> cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

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

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


(Goffredo Marocchi) #14

Hello Xiaodi,

A general principle of Swift, recently strengthened by proposals such as SE-0117, 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."

I think this is slightly misleading as that proposal dealt with classes being sealed by default outside of the current module while from your summary this would be also an explicit call for final by default which is not something the core team said explicitly or that the Swift community largely agrees with.

···

Sent from my iPhone

On 18 Jul 2016, at 08:50, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

A general principle of Swift, recently strengthened by proposals such as SE-0117, 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."


(Charlie Monroe) #15

+1. Makes sense this way.

···

On Jul 18, 2016, at 9:50 AM, Xiaodi Wu via swift-evolution <swift-evolution@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@gmail.com <mailto:xiaodi.wu@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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:xiaodi.wu@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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:xiaodi.wu@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@swift.org <mailto:swift-evolution@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@masters3d.com <mailto:cheyo@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. :slight_smile:

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@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@hartbit.com <mailto:david@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@swift.org <mailto:swift-evolution@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 :slight_smile:

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

Declarations inside the extension will, like declarations inside types, have a default access level of internal.
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.
An extension declared without an explicit access modifier will have the same access level as the type being extended.
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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

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

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

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


(David Hart) #16

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@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
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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, 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
[Review] SE-0119: Remove access modifiers from extensions
[Draft] Harmonize access modifiers for extensions
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, which is slated for preservation in Swift 3 as detailed in SE-0025. However, it is arguably surprising that, of two declarations spelled identically, one leads to a public API commitment while the other does not.

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.

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.

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.

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@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@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@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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

Harmonize access modifiers for extensions

Proposal: SE-XXXX
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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
[More to be added here]
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.

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.

Detailed design

Declarations inside the extension will, like declarations inside types, have a default access level of internal.
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.
An extension declared without an explicit access modifier will have the same access level as the type being extended.
An extension declared without protocol conformance may optionally use an explicit access modifier to provide an upper bound for the visibility of its members.
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.
Acknowledgments

Thanks to all discussants on the list, especially Adrian Zubarev and Jose Cheyo Jimenez.

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

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

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

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

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

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

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


(Xiaodi Wu) #17

Hello Xiaodi,

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."

I think this is slightly misleading as that proposal dealt with classes
being sealed by default outside of the current module while from your
summary this would be also an explicit call for final by default which is
not something the core team said explicitly or that the Swift community
largely agrees with.

Sorry, I will edit to clarify that sentence. My thinking was, Swift is
already internal by default; SE-0117 has added another layer, so that it's
internal -> public -> public open. In my mind, that's strengthening in that
the opt-in process for public APIs is now even more fine-grained.

···

On Mon, Jul 18, 2016 at 2:59 AM, Goffredo Marocchi <panajev@gmail.com> wrote:

Sent from my iPhone

On 18 Jul 2016, at 08:50, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

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."


(Adrian Zubarev) #18

+1 :slight_smile:

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 {}

// 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
// -> 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
``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.

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.

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.
With the exception in (1) we would need to allow access modifier on extension with protocol conformance to achieve the same result everywhere.
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@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@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
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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, 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
[Review] SE-0119: Remove access modifiers from extensions
[Draft] Harmonize access modifiers for extensions
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, which is slated for preservation in Swift 3 as detailed in SE-0025. However, it is arguably surprising that, of two declarations spelled identically, one leads to a public API commitment while the other does not.

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.

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.

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.

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@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@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@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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez <cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

Harmonize access modifiers for extensions

Proposal: SE-XXXX
Author: Xiaodi Wu
Status: Awaiting review
Review manager: TBD
Introduction

During discussion of SE-0119, 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
[More to be added here]
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.

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.

Detailed design

Declarations inside the extension will, like declarations inside types, have a default access level of internal.
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.
An extension declared without an explicit access modifier will have the same access level as the type being extended.
An extension declared without protocol conformance may optionally use an explicit access modifier to provide an upper bound for the visibility of its members.
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.
Acknowledgments

Thanks to all discussants on the list, especially Adrian Zubarev and Jose Cheyo Jimenez.

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

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

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

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

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

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


(Xiaodi Wu) #19

+1 :slight_smile:

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.

···

On Mon, Jul 18, 2016 at 6:09 AM, Adrian Zubarev via swift-evolution < swift-evolution@swift.org> wrote:

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@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@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@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@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@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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (
swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez < >>>>> cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

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

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

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

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


(Xiaodi Wu) #20

I have incorporated this new feedback and submitted a new PR. When (if?) it
comes up for review, I hope it will prove satisfactory. Thanks all!

···

On Mon, Jul 18, 2016 at 10:32 AM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Mon, Jul 18, 2016 at 6:09 AM, Adrian Zubarev via swift-evolution < > swift-evolution@swift.org> wrote:

+1 :slight_smile:

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@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@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@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@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@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@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@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@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. :confused:

--
Adrian Zubarev
Sent with Airmail

Am 17. Juli 2016 um 04:40:45, Xiaodi Wu via swift-evolution (
swift-evolution@swift.org) schrieb:

On Sat, Jul 16, 2016 at 7:56 PM, Jose Cheyo Jimenez < >>>>>> cheyo@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. :slight_smile:

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@swift.org> wrote:

On Sat, Jul 16, 2016 at 6:10 PM, David Hart <david@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@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 :slight_smile:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

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

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

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

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