Type-based ‘private’ access within a file

I think it neither mean nor capricious *if this is the last change we are ever going to do here*. We need to get it right, even if there’s a breaking source change. There’s a future-looking responsibility that is greater than the promises of minimal changes in the next version. If we are locking ourselves in to this, then let’s fix it once and for all. Or at least get damned close. If ’25 was a mistake then stand up, apologize, and fix it right.

The handcuffs are effectively self-inflicted. We can judge for ourselves if we actually need to be wearing them or if, for the greater good, we pop out of them for a moment and Do The Right Thing.

IMO, there is a case to be had for:
* Things truly private to a type (eg. a seek index that must be changed in step with buffer data and metadata)
* Things private to a set of related types in one file (eg. every case in C where you didn’t put something in the header)
* Things private to a type and extensions to it (eg. a count of characters in a string; extensions might be allowed to change this)
* Things private to a module (most everything else).
* Things others can override (subclasses, etc.).

Right now we have identifiers for most of these. What they’re called or when we use them is for another discussion; this is one of capability and need. The question is: does the language support clean code for all common use cases?

Lacking a proper “private” that is tightly-scoped to the type it’s defined in would make that a resounding No. Private means private, not Private But Everyone In The Room Can See It And Also Some People Near The Window. That’s something else.

Reading this discussion for the past few days, I get the sense that no one has really bothered to define the question properly. What are we trying to solve, specifically? For whom? What does that user expect? What are we trying to avoid? To succeed with? I see a lot of people talking about how they use things today and want to use them tomorrow, but what is the community goal here? Can it be stated in one or two sentences?

— Adam

···

On Apr 6, 2017, at 1:17 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 6, 2017, at 11:10, Vladimir.S <svabox@gmail.com> wrote:

On 06.04.2017 20:41, Jordan Rose via swift-evolution wrote:

Hi, -evolution. I’ve said this before, but *I think this new proposal is a
terrible idea*. It privileges types in a way that is damaging to the language.

[There isn't really anything new in my discussion below; everyone on-thread
is smart enough to have brought up these points already. But I wanted to go
on record about it, at least.]

Thank you for sharing your opinion regarding this subject.
Do I understand correctly, that *you* propose to just revert access levels and modifiers to Swift2 stage? (i.e. to drop current 'scoped-private' and rename 'fileprivate'->'private')
Or do you support to leave current 'scoped-private' under another name?

Neither, unfortunately. We accepted SE-0025, though I wish we hadn't; we named the two levels "private" and "fileprivate", though I wish we hadn't; and now there is lots of existing code relying on that, and it would be mean and capricious to force people to change that code when they migrated to Swift 4. I don't like where we ended up but Swift does not exist in a vacuum.

I hardly think it is “mean” or “capricious” to provide a *fully automated
migrator* to make the keywords better.

The discussion of SE-0159 reached a near-consensus that the access levels
should be spelled “private” and “scoped”.

I was shocked and dismayed that the core team did anything other than
enthusiastically adopt that resolution.

Nevin

···

On Thu, Apr 6, 2017 at 2:17 PM, Jordan Rose via swift-evolution < swift-evolution@swift.org> wrote:

We accepted SE-0025, though I wish we hadn't; we named the two levels
"private" and "fileprivate", though I wish we hadn't; and now there is lots
of existing code relying on that, and it would be mean and capricious to
force people to change that code when they migrated to Swift 4. I don't
like where we ended up but Swift does not exist in a vacuum.

Could we revert `private` to its Swift 2 meaning, but keep `fileprivate` as a compatibility alias with no plans to deprecate it until/unless we find that the keyword has nearly disappeared from use? That'd be a wart, but in the long run, I think it'd be less warty than living with an access control design we're not happy with.

···

On Apr 6, 2017, at 11:17 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Neither, unfortunately. We accepted SE-0025, though I wish we hadn't; we named the two levels "private" and "fileprivate", though I wish we hadn't; and now there is lots of existing code relying on that, and it would be mean and capricious to force people to change that code when they migrated to Swift 4. I don't like where we ended up but Swift does not exist in a vacuum.

--
Brent Royal-Gordon
Architechies

Sadly, no. The conclusion from SE-0159's review was that people are actively using scoped-private, even though you and I may not be.

Jordan

···

On Apr 6, 2017, at 17:04, Brent Royal-Gordon <brent@architechies.com> wrote:

On Apr 6, 2017, at 11:17 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Neither, unfortunately. We accepted SE-0025, though I wish we hadn't; we named the two levels "private" and "fileprivate", though I wish we hadn't; and now there is lots of existing code relying on that, and it would be mean and capricious to force people to change that code when they migrated to Swift 4. I don't like where we ended up but Swift does not exist in a vacuum.

Could we revert `private` to its Swift 2 meaning, but keep `fileprivate` as a compatibility alias with no plans to deprecate it until/unless we find that the keyword has nearly disappeared from use? That'd be a wart, but in the long run, I think it'd be less warty than living with an access control design we're not happy with.

Hi, -evolution. I’ve said this before, but *I think this new
proposal is a terrible idea*. It privileges types in a way that is
damaging to the language.

[There isn't really anything new in my discussion below; everyone
on-thread is smart enough to have brought up these points already.
But I wanted to go on record about it, at least.]

Thank you for sharing your opinion regarding this subject. Do I
understand correctly, that *you* propose to just revert access levels
and modifiers to Swift2 stage? (i.e. to drop current 'scoped-private'
and rename 'fileprivate'->'private') Or do you support to leave
current 'scoped-private' under another name?

Neither, unfortunately. We accepted SE-0025, though I wish we hadn't; we
named the two levels "private" and "fileprivate", though I wish we
hadn't; and now there is lots of existing code relying on that, and it
would be mean and capricious to force people to change that code when
they migrated to Swift 4. I don't like where we ended up but Swift does
not exist in a vacuum.

I see. Thank you for clarification.

I wonder, can't this be the situation that core team protects people "relying on that" when actually most(probably most, I don't know) people are asking "pleease.. rename this fileprivate to private back and keep 'scoped' for those, who actually need Swift3 scoped-private, its the best solution, we are ready to change our code(actually just use 100% automatic rename) in Swift4"?
(Btw, probably one should prepare such 'official' proposal so community can provide response directly during its 'official' review?? I don't know. The situation is at least strange currently IMO: nobody likes current state, seems like we have the best solution for this, new official proposals looks like some workaround instead of right solution and IMO produces more confusion than even current state)

Waiting for your thoughts regarding submodules etc, as IMO keeping 'fileprivate' keyword could be another one mistake we are making right now.

···

On 06.04.2017 21:17, Jordan Rose wrote:

On Apr 6, 2017, at 11:10, Vladimir.S <svabox@gmail.com> wrote:
On 06.04.2017 20:41, Jordan Rose via swift-evolution wrote:

Jordan

    We accepted SE-0025, though I wish we hadn't; we named the two levels
    "private" and "fileprivate", though I wish we hadn't; and now there
    is lots of existing code relying on that, and it would be mean and
    capricious to force people to change that code when they migrated to
    Swift 4. I don't like where we ended up but Swift does not exist in a
    vacuum.

I hardly think it is “mean” or “capricious” to provide a *fully automated
migrator* to make the keywords better.

The discussion of SE-0159 reached a near-consensus that the access levels
should be spelled “private” and “scoped”.

I was shocked and dismayed that the core team did anything other than
enthusiastically adopt that resolution.

I didn't get the sense of a "near-consensus", but one concern that I don't
remember being brought up on list was that it would make mixing Swift 3 and
Swift 4 much more confusing (including when dealing with sample code
snippets found online).

Probably this is why core team should raise a draft/pitch/review directly for that subject(renaming) and got the community's reply on it?
(I believe the response will be very positive)

As for mixing Swift3 and Swift4 and other drawbacks, they also could be discussed during the review of concrete subject(renaming) and IMO good solution can be found or decided that such drawbacks worth of these changes. At the end, this should make Swift better for long period of time, should fix the mistake, should(as I can see it currently) fits well with submodules, but drawbacks(other solutions also has their own drawbacks) will exist only during the adoption period. Especially given this is "the last chance to change anything in access modifiers".

···

On 06.04.2017 21:40, Jordan Rose via swift-evolution wrote:

On Apr 6, 2017, at 11:35, Nevin Brackett-Rozinsky via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Thu, Apr 6, 2017 at 2:17 PM, Jordan Rose via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Jordan

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

It does not remove the scoped access control, it only relaxes it in extensions to types in the same file.

Many of the use cases for scoped access given during the review of SE-0159 specifically related to restricting access between extensions in the same file. I don't personally use this, but it seems it is definitely used by some developers.

-BJ

Is there a reason this could not be implemented by putting all the sensitive stored properties in a separate type from the rest of the code?

-BJ

···

On Apr 7, 2017, at 9:23 AM, Matthew Johnson <matthew@anandabits.com> wrote:

The most common thing is to have some stored properties that are private and include a handful of fileprivate (or higher) methods that operate on these properties in the type declaration. All members that don’t need direct access to these properties are placed in extensions specifically to prevent the direct access to stored properties which they don’t need. This minimizes the lines of code with access to such properties.

-0.5

SE-0159 was rejected because it was determined that some developers are actively using strongly-scoped access control. This proposal removes that strong scoping, so I do not see how we can reasonably reject that proposal but accept this one.

I don’t know what you mean by strong in strong-scoped access, but your statement seems false. It does not remove the scoped access control, it only relaxes it in extensions to types in the same file.

This relaxation makes the resulting scoping decidedly less strong. It is no longer lexical and would require a user to consider all code in the file. This means the strong, compiler-verified guarantee of scoped access that a small number of lines can see a member is eliminated. The whole file must be considered. As others have noted, that defeats the primary purpose of having scoped access control in the first place.

The entire reason we're having this discussion is that "fileprivate" is such an awkward term for something that's so common in the language. I think the main thing we need to fix is the naming of that keyword.

The name of fileprivate is not reason for this proposal. fileprivate has an awkward name precisely because it was planned for it to be used less often. This proposal’s goal is to make private more attractive to fulfil that original goal. fileprivate’s awkwardness is good, because it attracts attention to it when it is used.

Your previous proposal eliminated this distinction entirely and if I understand correctly you still believe that is the best solution. With that in mind, do you really consider it important to call special attention to same-file, cross-type members? If we’re going to have a distinction in the language, do you really consider this a more important and useful distinction than the distinction supporting the use cases for scoped access? If the answer to either of those questions is no I find it hard to understand how this issue is not simply about having the ability to say `private` most of the time (which is a naming issue not a semantics issue).

···

On Apr 7, 2017, at 9:48 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

On 7 Apr 2017, at 15:41, BJ Homer via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I continue to believe that the best solution is to revert "private" to mean file scope as in Swift 2, and introduce a new "scoped" keyword for those developers who are specifically desiring the scoped functionality. This was rejected during the discussion because the migration would be too disruptive, but it is only disruptive if the migrator rewrites "private"->"scoped". I assert that most developers would not *want* that migration to happen; most developers use "private" because they want the default less-than-internal access control. The few developers who are using specifically scoped control can modify their code manually. Under this model, scoped access control is still available for those who need it, and most users can once again use "private" in cases where it is the natural default.

This proposal proposes that "fileprivate" would become a marker to call out cases where exceptional across-type access is happening. In practice, I don't believe that will happen, simply because there are many existing cases of "fileprivate" out there, and this proposal does not suggest migrating them.

I also disagree that it's useful to call out "fileprivate" as an exceptional case. It's slightly useful, I'll acknowledge, but it would be *more* useful to call out the exceptional cases where scope-only control is being used.

So I disagree with the proposal. But I give it only -0.5 because even with all of that, this is a better definition for "private" than the current one.

-BJ

On Apr 3, 2017, at 12:34 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift Community,

In rejecting SE-0159 <https://github.com/apple/swift-evolution/blob/master/proposals/0159-fix-private-access-levels.md&gt;, the core team described a potential direction we would like to investigate for “private” access control that admits a limited form of type-based access control within files. The core team is seeking some discussion here and a motivated volunteer to put together a proposal along these lines for review in the Swift 4 time-frame (i.e., very soon). To be clear, the core team it’s sure this is the right direction to go… but it appears promising and we would *love* to be able to settle the access-control issue.

The design, specifically, is that a “private” member declared within a type “X” or an extension thereof would be accessible from:

  * An extension of “X” in the same file
  * The definition of “X”, if it occurs in the same file
  * A nested type (or extension thereof) of one of the above that occurs in the same file

This design has a number of apparent benefits:
  + “private” becomes the right default for “less than whole module” visibility, and aligns well with Swift coding style that divides a type’s definition into a number of extensions.
  + “fileprivate” remains for existing use cases, but now it’s use it more rare, which has several advantages:
    + It fits well with the "progressive disclosure” philosophy behind Swift: you can use public/internal/private for a while before encountering and having to learn about “fileprivate” (note: we thought this was going to be true of SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt;, but we were clearly wrong)
    + When “fileprivate” occurs, it means there’s some interesting coupling between different types in the same file. That makes fileprivate a useful alert to the reader rather than, potentially, something that we routinely use and overlook so that we can separate implementations into extensions.
  + “private” is more closely aligned with other programming languages that use type-based access control, which can help programmers just coming to Swift. When they reach for “private”, they’re likely to get something similar to what they expect—with a little Swift twist due to Swift’s heavy use of extensions.
  + Loosening the access restrictions on “private” is unlikely to break existing code.

There are likely some drawbacks:
  - Developers using patterns that depend on the existing lexically-scoped access control of “private” may find this new interpretation of “private” to be insufficiently strict
  - Swift’s access control would go from “entirely lexical” to “partly lexical and partly type-based”, which can be viewed as being more complicated

Thoughts? Volunteer?

  - Doug
_______________________________________________
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

It does not remove the scoped access control, it only relaxes it in extensions to types in the same file.

Many of the use cases for scoped access given during the review of SE-0159 specifically related to restricting access between extensions in the same file. I don't personally use this, but it seems it is definitely used by some developers.

The most common thing is to have some stored properties that are private and include a handful of fileprivate (or higher) methods that operate on these properties in the type declaration. All members that don’t need direct access to these properties are placed in extensions specifically to prevent the direct access to stored properties which they don’t need. This minimizes the lines of code with access to such properties.

···

On Apr 7, 2017, at 10:06 AM, BJ Homer via swift-evolution <swift-evolution@swift.org> wrote:

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

The most common thing is to have some stored properties that are private and include a handful of fileprivate (or higher) methods that operate on these properties in the type declaration. All members that don’t need direct access to these properties are placed in extensions specifically to prevent the direct access to stored properties which they don’t need. This minimizes the lines of code with access to such properties.

Is there a reason this could not be implemented by putting all the sensitive stored properties in a separate type from the rest of the code?

This has already been discussed extensively in the threads. The problem with this approach under the current proposal is that there is no way to hide that type or its members from the rest of the file. It can be extended anywhere in the file which means the kind of encapsulation intended by users of scoped access is not really available. This is a kind of half-solution that relies on not extending the separate type and therefore offers a weaker guarantee while requiring extra boilerplate. It is also a kind of half-solution for those who wanted to revert SE-0025.

Setting aside source compatibility concerns for a brief moment, is there anyone who would choose this approach over reverting SE-0025, renaming the current modifier, or maintaining the current access modifiers? If this is nobody’s first choice that should be a big cautionary sign. It would indicate that this is the result of “design by committee” where nobody really likes it and it is at best the closest to consensus we could get. I don’t think “this is the best we can do because of source compatibility” is an appropriate justification for accepting this kind of solution. If source compatibility is such a paramount concern we should probably maintain the status quo or keep looking for a better, more source-compatible solution in the future (probably Swift 5).

I think one of the goals for Swift is to try and avoid that kind of decision making. If I’m going to be dissatisfied with part of the language I would rather it be for some other reason than that SE has caused the language to suffer from “design by committee” kinds of flaws.

···

On Apr 7, 2017, at 10:32 AM, BJ Homer <bjhomer@gmail.com> wrote:
On Apr 7, 2017, at 9:23 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

-BJ

After migrating several codebases, I think the best for me would be moving
in the direction explained in this proposal. For these reasons:

- In the migration to Swift 4, my team's code would work right away,
without any changes at all (well, at least because of this proposal).
- When my team have the time to do it, we can replace all of our
fileprivate usages for private ones, since we just use them to share
properties between same-file extensions.

So at the end this proposal will impact my team very little at first, we
will have less merge issues (hello Swift 3) and eventually the code will
be, for us, cleaner and easier to read. All the other proposals will not
give my team this smooth transition.

And, IMHO, I think that having access to really private details between two
types probably leads to programmer errors, so my next preferred step after
this one would be removing fileprivate altogether.

But I understand that Swift as a language must be gradually shaped.

···

On Fri, Apr 7, 2017 at 5:47 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Setting aside source compatibility concerns for a brief moment, is there
anyone who would choose this approach over reverting SE-0025, renaming the
current modifier, or maintaining the current access modifiers? If this is
nobody’s first choice that should be a big cautionary sign.

--
Víctor Pimentel

If that's the case, I don't think we should change the definition of `private` to something so unproven, and which violates our access control design's principles so much, right before the deadline. We do at least know that scoped `private` has some uses; we have no idea if file-and-type `private` will, but we *do* know it will eliminate many of the uses we've found for `private` (like ensuring that only a limited set of methods can use a property with tight invariants.)

I also think that allowing stored properties in same-file/same-module extensions will significantly improve the usefulness of `private` and reduce the need to have a same-type-same-file `private`. Right now, the fact that `private` properties can only be used from the main declaration requires that all types using `private` state be stuffed into that declaration. But it doesn't have to be that way, and once it is, `private` won't feel quite so restrictive.

(Besides, since we currently can't have two different `private` symbols on the same type in the same file, making this change later would be source-compatible except for overload resolution. We can open that box any time we want, but once we do, we can't close it again.)

So let's leave access control alone for now exactly as it is (including the "no duplicates" implementation limit), come up with a stored-properties-in-extensions strategy for Swift 5, and evaluate loosening `private` in a source-compatible way once we know what the experience will be like in the long run.

···

On Apr 3, 2017, at 2:19 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

Won’t making big modifications later be even more problematic than now, in the name of source stability?

Yes. Big changes along these lines will not be considered later. At best, it would be possible to "re-cast" existing behaviors in light of new features — that is, significantly changing *how we talk about those behaviors*, and changing how we understand them in the broader language, but not actually changing the behaviors themselves.

--
Brent Royal-Gordon
Architechies

If we wanted to do this, I think we'd want a `protected` modifier that was orthogonal to `internal` and `private` (which would probably revert to `fileprivate` semantics):

  struct Foo {
    private let bar: Int // Only visible in this file
    protected private let baz: Int // Only visible in this file and type
    
    let quux: Int // Only visible in this module
    protected let quuux: Int // Only visible in this module and type
  }

We might then consider extending `protected` to `public` and `open` scope.

I mention this not because I think type-based scoping is a good idea, but because if we're gonna do it, we shouldn't do it halfway.

···

On Apr 3, 2017, at 2:54 PM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

Moreover, I think that we need *additional* access level(to current 'private'), which will mean 'can be accessed from extensions and subtypes in the same *module*' to be able to split type's conformances to number of files and don't make implementation details accessible&visible for whole module. (there was 'extensible' modifier discussed previously).

--
Brent Royal-Gordon
Architechies

I’m concerned that we will have access control changes in a future version yet again, when light-weight modules, or other type of enforced namespace is introduced. Does the core team have any foresight on how this change would interact with such things? I had the same concern for SE-0159 as well.

There’s a implicit drawback to all access control changes that migrator/fix-its cannot fix: we organize our code with tools in the language. Some colleague of mine had came up with schemes that combines file scope and Swift 3 `private` to hide details among separate protocol extensions, for example. Code ends up in certain places for a reason and updating access control invalidate those reasons.

I hesitate to support any changes until we have some ideas for what “ultimate glory” looks like.

+1.

If we must make a change in Swift 4, the only change I can support for Swift 4 is renaming the existing access levels.

We don’t have to make a change in Swift 4. If there’s a change that can resolve this issue, great…

I still think this is a worthwhile goals.

That would cause some churn but can be automated and has no semantic impact. I feel strongly that the semantics of access control should remain the same until submodules and access control can be considered together as part of the theme of a larger Swift release. I believe the churn caused by continuing to poke at the semantics of access control without addressing the broader issues would be a mistake that would cause further frustration in the community.

… but if not, then let’s shelve access control changes until some time when we can considered it holistically with something like submodules, as you note above.

Won’t making big modifications later be even more problematic than now, in the name of source stability?

Yes. Big changes along these lines will not be considered later. At best, it would be possible to "re-cast" existing behaviors in light of new features — that is, significantly changing *how we talk about those behaviors*, and changing how we understand them in the broader language, but not actually changing the behaviors themselves.

John.

···

On Apr 3, 2017, at 5:11 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

On 3 Apr 2017, at 22:54, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 3, 2017, at 1:13 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Apr 3, 2017, at 2:55 PM, Daniel Duan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

As others have already pointed out, code has been developed and organized with the new scoped access model in mind. I think the frustration over a semantically neutral, fully automated migration to new names would be pretty minimal

The core team felt strongly that we couldn’t change these keywords. Source stability is important to Swift 4, and “don’t break source compatibility so much” is one of the top requests we hear from Swift developers, much more so than requests for specific new language features.

and certainly much less than the frustration over the suggested semantic change.

This isn’t clear to me. There could certainly be frustration over the suggested semantic change, for a number of reasons:

* It’s not as “tight” a meaning of private as the current scope-based private.
* It means we have a hybrid type-based/scope-based model.
* It’s the third meaning of ‘private’ in three years.

However, it is unlikely to break code (one would need to construct an ambiguity between two private declarations in different extensions of the same type in the same file), and causes zero code churn, because it’s widening the meaning of “private”, not changing it.

  - Doug

On Apr 3, 2017, at 11:34 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift Community,

In rejecting SE-0159 <https://github.com/apple/swift-evolution/blob/master/proposals/0159-fix-private-access-levels.md&gt;, the core team described a potential direction we would like to investigate for “private” access control that admits a limited form of type-based access control within files. The core team is seeking some discussion here and a motivated volunteer to put together a proposal along these lines for review in the Swift 4 time-frame (i.e., very soon). To be clear, the core team it’s sure this is the right direction to go… but it appears promising and we would *love* to be able to settle the access-control issue.

The design, specifically, is that a “private” member declared within a type “X” or an extension thereof would be accessible from:

  * An extension of “X” in the same file
  * The definition of “X”, if it occurs in the same file
  * A nested type (or extension thereof) of one of the above that occurs in the same file

This design has a number of apparent benefits:
  + “private” becomes the right default for “less than whole module” visibility, and aligns well with Swift coding style that divides a type’s definition into a number of extensions.
  + “fileprivate” remains for existing use cases, but now it’s use it more rare, which has several advantages:
    + It fits well with the "progressive disclosure” philosophy behind Swift: you can use public/internal/private for a while before encountering and having to learn about “fileprivate” (note: we thought this was going to be true of SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt;, but we were clearly wrong)
    + When “fileprivate” occurs, it means there’s some interesting coupling between different types in the same file. That makes fileprivate a useful alert to the reader rather than, potentially, something that we routinely use and overlook so that we can separate implementations into extensions.
  + “private” is more closely aligned with other programming languages that use type-based access control, which can help programmers just coming to Swift. When they reach for “private”, they’re likely to get something similar to what they expect—with a little Swift twist due to Swift’s heavy use of extensions.
  + Loosening the access restrictions on “private” is unlikely to break existing code.

There are likely some drawbacks:
  - Developers using patterns that depend on the existing lexically-scoped access control of “private” may find this new interpretation of “private” to be insufficiently strict
  - Swift’s access control would go from “entirely lexical” to “partly lexical and partly type-based”, which can be viewed as being more complicated

Thoughts? Volunteer?

  - Doug
_______________________________________________
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

I’m concerned that we will have access control changes in a future version yet again, when light-weight modules, or other type of enforced namespace is introduced. Does the core team have any foresight on how this change would interact with such things? I had the same concern for SE-0159 as well.

There’s a implicit drawback to all access control changes that migrator/fix-its cannot fix: we organize our code with tools in the language. Some colleague of mine had came up with schemes that combines file scope and Swift 3 `private` to hide details among separate protocol extensions, for example. Code ends up in certain places for a reason and updating access control invalidate those reasons.

I hesitate to support any changes until we have some ideas for what “ultimate glory” looks like.

+1.

If we must make a change in Swift 4, the only change I can support for Swift 4 is renaming the existing access levels.

We don’t have to make a change in Swift 4. If there’s a change that can resolve this issue, great…

That would cause some churn but can be automated and has no semantic impact. I feel strongly that the semantics of access control should remain the same until submodules and access control can be considered together as part of the theme of a larger Swift release. I believe the churn caused by continuing to poke at the semantics of access control without addressing the broader issues would be a mistake that would cause further frustration in the community.

… but if not, then let’s shelve access control changes until some time when we can considered it holistically with something like submodules, as you note above.

This is certainly what I would prefer. I only mention renaming because there is such strong interest in changing something. I would be happy to defer this topic and have been arguing for that approach ever since your note that only SE-0159 would be considered in scope for Swift 4.

As others have already pointed out, code has been developed and organized with the new scoped access model in mind. I think the frustration over a semantically neutral, fully automated migration to new names would be pretty minimal

The core team felt strongly that we couldn’t change these keywords. Source stability is important to Swift 4, and “don’t break source compatibility so much” is one of the top requests we hear from Swift developers, much more so than requests for specific new language features.

That’s fair.

and certainly much less than the frustration over the suggested semantic change.

This isn’t clear to me. There could certainly be frustration over the suggested semantic change, for a number of reasons:

* It’s not as “tight” a meaning of private as the current scope-based private.
* It means we have a hybrid type-based/scope-based model.
* It’s the third meaning of ‘private’ in three years.

However, it is unlikely to break code (one would need to construct an ambiguity between two private declarations in different extensions of the same type in the same file), and causes zero code churn, because it’s widening the meaning of “private”, not changing it.

I’m speculating based on my read of the community here as well as other Swift developers I know. I could be wrong, but my sense is that the items you list would cause more frustration than renaming, especially if the name change purged `fileprivate`. I don’t know anyone outside the evolution community who I think would complain if access control was left alone for a while.

I would quite like the model proposed here actually as it does make private a very very sane default, fits with Swift's progressive disclosure goals and its architecture, as well as eases the transition of developers from other major languages which is a massive boon to this community too without nasty side effects or sacrifices to Swift's ideals. +1 to this change :).

I think this proposal is worth acting upon rather than waiting another year for something which, looking ahead, is not sure to be overhauled so much before Swift 5 is finalised.

···

Sent from my iPhone

On 3 Apr 2017, at 22:03, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 3, 2017, at 3:54 PM, Douglas Gregor <dgregor@apple.com> wrote:

On Apr 3, 2017, at 1:13 PM, Matthew Johnson <matthew@anandabits.com> wrote:
On Apr 3, 2017, at 2:55 PM, Daniel Duan via swift-evolution <swift-evolution@swift.org> wrote:

Some were not happy with the changes in Swift 3 but I don’t hear too much about it off the list anymore now that the migration is over and people have adapted.

  - Doug

On Apr 3, 2017, at 11:34 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Hello Swift Community,

In rejecting SE-0159, the core team described a potential direction we would like to investigate for “private” access control that admits a limited form of type-based access control within files. The core team is seeking some discussion here and a motivated volunteer to put together a proposal along these lines for review in the Swift 4 time-frame (i.e., very soon). To be clear, the core team it’s sure this is the right direction to go… but it appears promising and we would *love* to be able to settle the access-control issue.

The design, specifically, is that a “private” member declared within a type “X” or an extension thereof would be accessible from:

  * An extension of “X” in the same file
  * The definition of “X”, if it occurs in the same file
  * A nested type (or extension thereof) of one of the above that occurs in the same file

This design has a number of apparent benefits:
  + “private” becomes the right default for “less than whole module” visibility, and aligns well with Swift coding style that divides a type’s definition into a number of extensions.
  + “fileprivate” remains for existing use cases, but now it’s use it more rare, which has several advantages:
    + It fits well with the "progressive disclosure” philosophy behind Swift: you can use public/internal/private for a while before encountering and having to learn about “fileprivate” (note: we thought this was going to be true of SE-0025, but we were clearly wrong)
    + When “fileprivate” occurs, it means there’s some interesting coupling between different types in the same file. That makes fileprivate a useful alert to the reader rather than, potentially, something that we routinely use and overlook so that we can separate implementations into extensions.
  + “private” is more closely aligned with other programming languages that use type-based access control, which can help programmers just coming to Swift. When they reach for “private”, they’re likely to get something similar to what they expect—with a little Swift twist due to Swift’s heavy use of extensions.
  + Loosening the access restrictions on “private” is unlikely to break existing code.

There are likely some drawbacks:
  - Developers using patterns that depend on the existing lexically-scoped access control of “private” may find this new interpretation of “private” to be insufficiently strict
  - Swift’s access control would go from “entirely lexical” to “partly lexical and partly type-based”, which can be viewed as being more complicated

Thoughts? Volunteer?

  - Doug
_______________________________________________
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

I’m concerned that we will have access control changes in a future version yet again, when light-weight modules, or other type of enforced namespace is introduced. Does the core team have any foresight on how this change would interact with such things? I had the same concern for SE-0159 as well.

There’s a implicit drawback to all access control changes that migrator/fix-its cannot fix: we organize our code with tools in the language. Some colleague of mine had came up with schemes that combines file scope and Swift 3 `private` to hide details among separate protocol extensions, for example. Code ends up in certain places for a reason and updating access control invalidate those reasons.

I hesitate to support any changes until we have some ideas for what “ultimate glory” looks like.

+1.

If we must make a change in Swift 4, the only change I can support for Swift 4 is renaming the existing access levels.

We don’t have to make a change in Swift 4. If there’s a change that can resolve this issue, great…

I still think this is a worthwhile goals.

That would cause some churn but can be automated and has no semantic impact. I feel strongly that the semantics of access control should remain the same until submodules and access control can be considered together as part of the theme of a larger Swift release. I believe the churn caused by continuing to poke at the semantics of access control without addressing the broader issues would be a mistake that would cause further frustration in the community.

… but if not, then let’s shelve access control changes until some time when we can considered it holistically with something like submodules, as you note above.

Won’t making big modifications later be even more problematic than now, in the name of source stability?

Yes. Big changes along these lines will not be considered later. At best, it would be possible to "re-cast" existing behaviors in light of new features — that is, significantly changing *how we talk about those behaviors*, and changing how we understand them in the broader language, but not actually changing the behaviors themselves.

That’s why I don’t buy the “lets postpone this discussion to a future submodule design” argument. Let’s get this in a reasonable state now :)

···

On 3 Apr 2017, at 23:19, John McCall <rjmccall@apple.com> wrote:

On Apr 3, 2017, at 5:11 PM, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 3 Apr 2017, at 22:54, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 3, 2017, at 1:13 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Apr 3, 2017, at 2:55 PM, Daniel Duan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

John.

As others have already pointed out, code has been developed and organized with the new scoped access model in mind. I think the frustration over a semantically neutral, fully automated migration to new names would be pretty minimal

The core team felt strongly that we couldn’t change these keywords. Source stability is important to Swift 4, and “don’t break source compatibility so much” is one of the top requests we hear from Swift developers, much more so than requests for specific new language features.

and certainly much less than the frustration over the suggested semantic change.

This isn’t clear to me. There could certainly be frustration over the suggested semantic change, for a number of reasons:

* It’s not as “tight” a meaning of private as the current scope-based private.
* It means we have a hybrid type-based/scope-based model.
* It’s the third meaning of ‘private’ in three years.

However, it is unlikely to break code (one would need to construct an ambiguity between two private declarations in different extensions of the same type in the same file), and causes zero code churn, because it’s widening the meaning of “private”, not changing it.

  - Doug

On Apr 3, 2017, at 11:34 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift Community,

In rejecting SE-0159 <https://github.com/apple/swift-evolution/blob/master/proposals/0159-fix-private-access-levels.md&gt;, the core team described a potential direction we would like to investigate for “private” access control that admits a limited form of type-based access control within files. The core team is seeking some discussion here and a motivated volunteer to put together a proposal along these lines for review in the Swift 4 time-frame (i.e., very soon). To be clear, the core team it’s sure this is the right direction to go… but it appears promising and we would *love* to be able to settle the access-control issue.

The design, specifically, is that a “private” member declared within a type “X” or an extension thereof would be accessible from:

  * An extension of “X” in the same file
  * The definition of “X”, if it occurs in the same file
  * A nested type (or extension thereof) of one of the above that occurs in the same file

This design has a number of apparent benefits:
  + “private” becomes the right default for “less than whole module” visibility, and aligns well with Swift coding style that divides a type’s definition into a number of extensions.
  + “fileprivate” remains for existing use cases, but now it’s use it more rare, which has several advantages:
    + It fits well with the "progressive disclosure” philosophy behind Swift: you can use public/internal/private for a while before encountering and having to learn about “fileprivate” (note: we thought this was going to be true of SE-0025 <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md&gt;, but we were clearly wrong)
    + When “fileprivate” occurs, it means there’s some interesting coupling between different types in the same file. That makes fileprivate a useful alert to the reader rather than, potentially, something that we routinely use and overlook so that we can separate implementations into extensions.
  + “private” is more closely aligned with other programming languages that use type-based access control, which can help programmers just coming to Swift. When they reach for “private”, they’re likely to get something similar to what they expect—with a little Swift twist due to Swift’s heavy use of extensions.
  + Loosening the access restrictions on “private” is unlikely to break existing code.

There are likely some drawbacks:
  - Developers using patterns that depend on the existing lexically-scoped access control of “private” may find this new interpretation of “private” to be insufficiently strict
  - Swift’s access control would go from “entirely lexical” to “partly lexical and partly type-based”, which can be viewed as being more complicated

Thoughts? Volunteer?

  - Doug
_______________________________________________
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

Won’t making big modifications later be even more problematic than now, in the name of source stability?

Yes. Big changes along these lines will not be considered later. At best, it would be possible to "re-cast" existing behaviors in light of new features — that is, significantly changing *how we talk about those behaviors*, and changing how we understand them in the broader language, but not actually changing the behaviors themselves.

If that's the case, I don't think we should change the definition of `private` to something so unproven, and which violates our access control design's principles so much, right before the deadline. We do at least know that scoped `private` has some uses; we have no idea if file-and-type `private` will, but we *do* know it will eliminate many of the uses we've found for `private` (like ensuring that only a limited set of methods can use a property with tight invariants.)

It’s not necessarily unproven. It’s actually much closer to what private in other languages look like (with Swift extensions in the mix). And it would still allow many uses of private, like Drew Crawford’s ThreadsafeWrapper example from the 23rd of March.

I also think that allowing stored properties in same-file/same-module extensions will significantly improve the usefulness of `private` and reduce the need to have a same-type-same-file `private`. Right now, the fact that `private` properties can only be used from the main declaration requires that all types using `private` state be stuffed into that declaration. But it doesn't have to be that way, and once it is, `private` won't feel quite so restrictive.

I think that would not help. We would still be constantly juggling between private and fileprivate depending if we are trying to access a property in the same scope or not. When writing types as a minimal internal interface followed by a set of grouping and conformance extensions, you would still constantly bump against limitations of private and resort to fileprivate.

(Besides, since we currently can't have two different `private` symbols on the same type in the same file, making this change later would be source-compatible except for overload resolution. We can open that box any time we want, but once we do, we can't close it again.)

John McCall stated this is the last opportunity to improve the status-quo:

I agree. This is why we asked swift-evolution to consider this last tweak: it is realistically the last opportunity to do it.

···

On 3 Apr 2017, at 23:55, Brent Royal-Gordon <brent@architechies.com> wrote:

On Apr 3, 2017, at 2:19 PM, John McCall via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

So let's leave access control alone for now exactly as it is (including the "no duplicates" implementation limit), come up with a stored-properties-in-extensions strategy for Swift 5, and evaluate loosening `private` in a source-compatible way once we know what the experience will be like in the long run.

--
Brent Royal-Gordon
Architechies

Moreover, I think that we need *additional* access level(to current
'private'), which will mean 'can be accessed from extensions and subtypes
in the same *module*' to be able to split type's conformances to number
of files and don't make implementation details accessible&visible for
whole module. (there was 'extensible' modifier discussed previously).

If we wanted to do this, I think we'd want a `protected` modifier that was
orthogonal to `internal` and `private` (which would probably revert to
`fileprivate` semantics):

I don't think so, IMO it seems like over-complicated structure of access levels. I believe it is a required minimum to have current 'private' and something similar scope(type)-based but with wider scope. (in addition to public/internal/fileprivate). IMO this will resolve major percent of problems raised in the thread.

···

On 04.04.2017 0:59, Brent Royal-Gordon wrote:

On Apr 3, 2017, at 2:54 PM, Vladimir.S via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

struct Foo {
private let bar: Int// Only visible in this file
protected private let baz: Int// Only visible in this file and type
let quux: Int// Only visible in this module
protected let quuux: Int// Only visible in this module and type
}

We might then consider extending `protected` to `public` and `open` scope.

I mention this not because I think type-based scoping is a good idea, but
because if we're gonna do it, we shouldn't do it halfway.

--
Brent Royal-Gordon
Architechies

The proposed relaxation to 'private' is indeed small, and it makes Swift 3's "private" a more acceptable "soft default" for restricted access, but it also removes the ability of Swift to define a truly scoped access control, which some developers have found highly useful.

I would prefer accepting this proposal over doing nothing, as I think "private" is broken right now as a soft default, which is unfortunate for a language that will be used by so many new programmers. But I think renaming access controls without a large migration, as I suggested earlier, would be better.

-BJ

···

On Apr 4, 2017, at 12:45 AM, Goffredo Marocchi via swift-evolution <swift-evolution@swift.org> wrote:

Considering how small this private rule relaxation is, it seems strange to swat away this proposal...