[Review] SE-0159: Fix Private Access Levels


(Matt Gallagher) #1

What is your evaluation of the proposal?

I disagree with this proposal. It removes functionality that I actively use.

This proposal aims to revert SE-0025 without really addressing the aims of that proposal, merely dismissing the result as "actively harmful" without defining what that means. SE-0159 raises the complaint that "private" is syntactically more natural default while "fileprivate" is a more useful default. On this point, I agree but the proposal is not about mere renaming.

The other discussion in the proposal is to ask the questions:

  1. is that distinction between private and fileprivate actively used by the larger community of Swift developers

  2. if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language?

Fair questions but despite the proposal claiming "This proposal argues that answer to both questions is no", the proposal offers no *arguments* for the answers, it merely states a position.

For this reason, I feel the proposal is unreasonably dismissive of the aims of SE-0025.

Frankly, both these questions have subjective answers based on how programmers tend to design their programs. I personally like to build functionality using lots of very tiny types (many just 4 or 5 lines long), therefore, I frequently put multiple types in the same file (they're part of the same functionality, even if they're not part of the same type). However, I want to have actual interfaces and implementation hiding between them otherwise there's always the possibility of accidentally abusing the interface to each type. An access modifier narrower than the file, like the current scoped "private", is the *only* way to achieve this.

Reverting SE-0025 means the only way to have enforced interfaces between types is to place them in separate files. This is counterproductive for tiny types that form a single conceptual entity. Separate files also requires whole-program optimization for optimal performance.

The only conclusion I can make is that programmers in favor of this proposal simply don't program this way. However, I find it insulting that this proposal is essentially saying: your way of designing and structuring programs is wrong; you must use big monolithic types in their own files and endure reduced compilation (whole-program optimization) or runtime performance (no inlining between files with whole-program off).

I can't help but feel that this proposal is really misdirected frustration. Programmers who don't use clusters of tiny types in a single file shouldn't care about the existence of a scoped access modifier because it shouldn't affect them – they should use file access modifiers and be done. Yet apparently, it is file access modifier advocates pushing this proposal.

It really seems like the existence of a scoped access modifier is taking the blame for people's frustration that the simpler keyword ("private") is a less good default than the clunky keyword ("fileprivate"). I personally agree that the behavior or "fileprivate" is probably a better default so I understand the desire to give "private" back that meaning again. However, I don't want to lose a scoped access modifier because it is *useful* (for reasons of both project structure and compilation or runtime performance).

So... thumbs down from me. However, if someone wants to rename fileprivate -> private and rename private -> scope (or something) I'd be more supportive.

Regards,
Matt Gallagher.


(Matthew Johnson) #2

What is your evaluation of the proposal?

I disagree with this proposal. It removes functionality that I actively use.

This proposal aims to revert SE-0025 without really addressing the aims of that proposal, merely dismissing the result as "actively harmful" without defining what that means. SE-0159 raises the complaint that "private" is syntactically more natural default while "fileprivate" is a more useful default. On this point, I agree but the proposal is not about mere renaming.

The other discussion in the proposal is to ask the questions:

  1. is that distinction between private and fileprivate actively used by the larger community of Swift developers

  2. if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language?

Fair questions but despite the proposal claiming "This proposal argues that answer to both questions is no", the proposal offers no *arguments* for the answers, it merely states a position.

For this reason, I feel the proposal is unreasonably dismissive of the aims of SE-0025.

Frankly, both these questions have subjective answers based on how programmers tend to design their programs. I personally like to build functionality using lots of very tiny types (many just 4 or 5 lines long), therefore, I frequently put multiple types in the same file (they're part of the same functionality, even if they're not part of the same type). However, I want to have actual interfaces and implementation hiding between them otherwise there's always the possibility of accidentally abusing the interface to each type. An access modifier narrower than the file, like the current scoped "private", is the *only* way to achieve this.

Reverting SE-0025 means the only way to have enforced interfaces between types is to place them in separate files. This is counterproductive for tiny types that form a single conceptual entity. Separate files also requires whole-program optimization for optimal performance.

The only conclusion I can make is that programmers in favor of this proposal simply don't program this way. However, I find it insulting that this proposal is essentially saying: your way of designing and structuring programs is wrong; you must use big monolithic types in their own files and endure reduced compilation (whole-program optimization) or runtime performance (no inlining between files with whole-program off).

I can't help but feel that this proposal is really misdirected frustration. Programmers who don't use clusters of tiny types in a single file shouldn't care about the existence of a scoped access modifier because it shouldn't affect them – they should use file access modifiers and be done. Yet apparently, it is file access modifier advocates pushing this proposal.

It really seems like the existence of a scoped access modifier is taking the blame for people's frustration that the simpler keyword ("private") is a less good default than the clunky keyword ("fileprivate"). I personally agree that the behavior or "fileprivate" is probably a better default so I understand the desire to give "private" back that meaning again. However, I don't want to lose a scoped access modifier because it is *useful* (for reasons of both project structure and compilation or runtime performance).

So... thumbs down from me. However, if someone wants to rename fileprivate -> private and rename private -> scope (or something) I'd be more supportive.

Huge +1 to everything Matt says here.

Elsewhere it has been argued that submodules allowing for a submodule scope can be combined with file scope to address some of the use cases for scoped access control. This is true, but I want to point out that this combination most definitely does not address the use cases Matt describes here. I often also create small types which are in the same file with other types and benefit from scoped access control. As Matt points out, there simply isn’t any other way to address this use case. It would be a shame to see Swift revert to not properly supporting this style of code.

It is also true that submodules (depending on their design) can address some of the use cases for file level scope. In fact some people have suggested we might be able to drop file level scope after introducing submodules. I wouldn’t want to see us do that (both are useful), but forced to choose between file scope and lexical scope in a language with submodules I may well choose lexical scope.

Even if we assume that we want to eliminate either file or lexical scope I think it is preliminary to make a decision about which to eliminate. The community should make this decision when we know what submodules look like and what kind of use cases they will address well, address (but maybe not so well) and not address at all.

If we feel compelled to make a change now we should choose to change the keywords. This will make most or all of the proponents of scoped access happy. It also solves the most prominent problem with `fileprivate` (its ungainly name). My impression is that some people really want to ban scoped access but others just want to be able to use `private` to refer to file scope. The second camp would also be happy with renaming. Two camps would be happy with this approach while a third probably wouldn’t.

Another argument in support of renaming is that scoped access was originally proposed as introducing a new keyword and leaving private alone. One primary reason this approach was abandoned is that there was no consensus as to what the keyword for scoped access should be. As far as I can tell, consensus has now formed that if we rename it we should simply call it `scoped`. I suspect that if we had chosen this approach originally there would be far less complaints and we probably would not be reviewing a proposal to revert it. This change would better align the language with the original intent of the proposal and address the biggest complaint about fileprivate.

We could choose to make this change in Swift 4. We could also choose to maintain the status quo in Swift 4 and address access control and submodules in the future as part of a cohesive theme for a Swift release. I would be happy with either choice. I would be extremely disappointed if it was decided that the use cases addressed by scoped access are not important enough to be solved by a language feature and instead relegated to naming conventions and linters.

Matthew

···

On Mar 23, 2017, at 1:22 AM, Matt Gallagher via swift-evolution <swift-evolution@swift.org> wrote:

Regards,
Matt Gallagher.

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


(Matthew Johnson) #3

I can't help but feel that this proposal is really misdirected frustration. Programmers who don't use clusters of tiny types in a single file shouldn't care about the existence of a scoped access modifier because it shouldn't affect them – they should use file access modifiers and be done. Yet apparently, it is file access modifier advocates pushing this proposal.

It is equally frustrating that those on the opposite side of this proposal keep indicating “just don’t pay attention to it” is an acceptable answer to the language growing an entire axis of confusion to its access control (i.e., a wart) so early in its life.

I think it’s likely that a non-trivial degree of any confusion is related to the mistake we made in choosing the names. Both `fileprivate` and `private` include the word `private` in their name. If we had left `private` alone and introduces scoped access with the name `scoped` I think the difference would have been much more clear to most people who have been confused.

···

On Mar 23, 2017, at 10:54 AM, Zach Waldowski via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 23, 2017, at 2:22 AM, Matt Gallagher via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sincerely,
Zachary Waldowski
Sent from my Mac

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


(Zachary Waldowski) #4

It is equally frustrating that those on the opposite side of this proposal keep indicating “just don’t pay attention to it” is an acceptable answer to the language growing an entire axis of confusion to its access control (i.e., a wart) so early in its life.

Sincerely,
Zachary Waldowski

···

On Mar 23, 2017, at 2:22 AM, Matt Gallagher via swift-evolution <swift-evolution@swift.org> wrote:
I can't help but feel that this proposal is really misdirected frustration. Programmers who don't use clusters of tiny types in a single file shouldn't care about the existence of a scoped access modifier because it shouldn't affect them – they should use file access modifiers and be done. Yet apparently, it is file access modifier advocates pushing this proposal.

Sent from my Mac


(Michel Fortin) #5

An interesting question when digging into the past is: would the core team have accepted the "scoped" proposal knowing what we know today? It's hard to judge form the outside how much the acceptance of scoped-private by the core team at that time was linked to it being able to replace most instances of file-private, but I'm under the impression that it was the tipping point.

The current proposal, as written, is to return to the Swift 2 model, making it as if the initial `scoped` proposal for Swift 3 had been rejected. Which brings another interesting question: let's assume for a moment that this proposal to revert to the Swift 2 model is accepted as is... should we also backtrack on the idea of allowing `public` members inside of `private` classes? As I remember, this was added to Swift 3 to make it possible to have `fileprivate` members inside of `private` types. This proposal leaves this unchanged though, which means it's not a complete revert to the Swift 2 model. Is this an oversight? Maybe it'd break source compatibility a bit too much.

···

Le 23 mars 2017 à 12:03, Matthew Johnson via swift-evolution <swift-evolution@swift.org> a écrit :

I think it’s likely that a non-trivial degree of any confusion is related to the mistake we made in choosing the names. Both `fileprivate` and `private` include the word `private` in their name. If we had left `private` alone and introduces scoped access with the name `scoped` I think the difference would have been much more clear to most people who have been confused.

--
Michel Fortin
https://michelf.ca


(Drew Crawford) #6

This is because the anti-SE25 camp advance arguments of the form "you can replace all your private with fileprivate and it will still work". That is not actually true as examples in this thread have shown, but to whatever extent it is *typical* it would imply that the programmer does not need to engage with the "cognitive load" of private at all because they can simply use fileprivate instead.

I don't find that argument at all convincing, but it does seem clear that if one accepts the premise that private is redundant, there would be no need to learn what it does. I think it would be better presented as "since there is a need to understand what it does, we know it is not redundant."

···

On Mar 23, 2017, at 10:54 AM, Zach Waldowski via swift-evolution <swift-evolution@swift.org> wrote:

It is equally frustrating that those on the opposite side of this proposal keep indicating “just don’t pay attention to it” is an acceptable answer to the language growing an entire axis of confusion to its access control (i.e., a wart) so early in its life.


(Drew Crawford) #7

I would like to separately concur with (most of) Matt's excellent review. He identifies what I think the core issues here, which are
People code in different styles. A scoped keyword is more useful in some styles and less useful in others, and this debate is in many ways a proxy war about programming style.
Most of the "solutions" proposed boil down to telling private users to adopt a different programming style. Instead we should be making Swift a great language for a *wider* diversity of programming styles as it expands to new platforms and solves new problems.
The complexity argument seems weak or even absent. It consists largely of the informal observation that 3 keywords are better than 4, which may "feel true" but does not have the research behind it of a Goto Considered Harmful™. Instead, most of the research on usage and impact are coming from those trying to keep it, which does not seem like their burden to meet.

What is your evaluation of the proposal?

I disagree with this proposal. It removes functionality that I actively use.

This proposal aims to revert SE-0025 without really addressing the aims of that proposal, merely dismissing the result as "actively harmful" without defining what that means. SE-0159 raises the complaint that "private" is syntactically more natural default while "fileprivate" is a more useful default. On this point, I agree but the proposal is not about mere renaming.

The other discussion in the proposal is to ask the questions:

1. is that distinction between private and fileprivate actively used by the larger community of Swift developers

2. if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language?

Fair questions but despite the proposal claiming "This proposal argues that answer to both questions is no", the proposal offers no *arguments* for the answers, it merely states a position.

For this reason, I feel the proposal is unreasonably dismissive of the aims of SE-0025.

Frankly, both these questions have subjective answers based on how programmers tend to design their programs. I personally like to build functionality using lots of very tiny types (many just 4 or 5 lines long), therefore, I frequently put multiple types in the same file (they're part of the same functionality, even if they're not part of the same type). However, I want to have actual interfaces and implementation hiding between them otherwise there's always the possibility of accidentally abusing the interface to each type. An access modifier narrower than the file, like the current scoped "private", is the *only* way to achieve this.

Reverting SE-0025 means the only way to have enforced interfaces between types is to place them in separate files. This is counterproductive for tiny types that form a single conceptual entity. Separate files also requires whole-program optimization for optimal performance.

The only conclusion I can make is that programmers in favor of this proposal simply don't program this way. However, I find it insulting that this proposal is essentially saying: your way of designing and structuring programs is wrong; you must use big monolithic types in their own files and endure reduced compilation (whole-program optimization) or runtime performance (no inlining between files with whole-program off).

I can't help but feel that this proposal is really misdirected frustration. Programmers who don't use clusters of tiny types in a single file shouldn't care about the existence of a scoped access modifier because it shouldn't affect them – they should use file access modifiers and be done. Yet apparently, it is file access modifier advocates pushing this proposal.

It really seems like the existence of a scoped access modifier is taking the blame for people's frustration that the simpler keyword ("private") is a less good default than the clunky keyword ("fileprivate"). I personally agree that the behavior or "fileprivate" is probably a better default so I understand the desire to give "private" back that meaning again. However, I don't want to lose a scoped access modifier because it is *useful* (for reasons of both project structure and compilation or runtime performance).

So... thumbs down from me. However, if someone wants to rename fileprivate -> private and rename private -> scope (or something) I'd be more supportive.

Regards,
Matt Gallagher.

···

On March 23, 2017 at 1:22:49 AM, Matt Gallagher via swift-evolution (swift-evolution@swift.org) wrote:

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


(Matt Gallagher) #8

Without retracting any of the statements I made in my previous message:

  https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170320/034336.html

I'd like to point out that on a 1 to 10 scale of Swift past and potential changes that I'm passionate about – with a perfect 10 reserved for the Swift Ownership Manifesto and a 1 being something trivial like SE-0106 (Add a macOS Alias for the OSX Platform) – this issue rates around a 3 for me. I care but not a lot.

I'm mentioning this because a number of people on Twitter are commenting that discussion on this issue has gotten a little quarrelsome and I'm sorry if I've had a part in that. I only weighed-in to state that I have an opinion, not to draw a line in the sand and dig a bunker.

I'm fully aware that scoped access modifiers are basically an issue of aesthetics; allowing you to keep two entities that need interface-hiding in the same file, rather than in separate files. On that point, the whole issue could be seen as bike-shedding.

Further, even for my own "primary use case" that I personally gave here:

  https://gist.github.com/mattgallagher/b93c6e587488d60a68e4cc0318a7c356

I can think of additional abstractions that would make the `private` members inaccessible while still keeping both View-Model and View-Binding in the same file e.g.

  a) Wrapping the `input` and `output` members in a generic wrapper that lives in another file (and so can take advantage of interface-hiding between files) and handles the required input-hidden/managed, output-exposed pattern

  b) Building a series of libdispatch/reactive/whatever closures up in the `init` method that contain and self-manage the internallyMaintainedState – so it doesn't need to reside the View-Model at all – and merely store an opaque KeepAlive instance in the View-Model to anchor the lifetime

Involving more abstractions like this or setting up an opaque, self-managing entities does mean more work – both implementation time and conceptual gymnastics – but these approaches could deliver similar aesthetics without needing scoped access modifiers. There are potential performance implications involved in adding abstractions and closures but these can be handled as they arise.

Regards,
Matt Gallagher.


(Carl Brown1) #9

Hello Swift community,

The review of SE-0159 "Fix Private Access Levels" begins now and runs

through March 27, 2017. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0159-fix-private-access-levels.md

Reviews are an important part of the Swift evolution process. All reviews

should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution<

https://lists.swift.org/mailman/listinfo/swift-evolution>

or, if you would like to keep your feedback private, directly to the

review manager. When replying, please try to keep the proposal link at the
top of the message:

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0159-fix-private-access-levels.md

Reply text

What is your evaluation of the proposal?

-1. No. Please don't remove a useful feature and break existing code in
thousands of places just to prevent some confusion due to the similarity of
two keywords.

Is the problem being addressed significant enough to warrant a change to

Swift?

No. Not at all.

Does this proposal fit well with the feel and direction of Swift?

No. This explicitly removes a feature that the community uses and takes us
back to Swift 2.2. That's literally the opposite of the "direction of
Swift".

If you have used other languages or libraries with a similar feature, how

do you feel that this proposal compares to those?

I've used a number of different languages with various scoping and access
modifiers, and there is enough variation in other languages that there's no
clear requirement that Swift should agree with any other languages' usage.

How much effort did you put into your review? A glance, a quick reading,

or an in-depth study?

I reviewed the usage of `private` and `fileprivate` in the
swift-corelibs-foundation and swift-corelibs-libdispatch repositories.
There are 500+ instances across those two repositories (386 private and 131
fileprivate on the version of those libraries I already had checked out on
my laptop to work on the bug I'm currently chasing).

To be honest, the open-source version of Foundation still has a long way to
go to get the level of quality of the existing Objective-C frameworks, and
we already have enough work to do without having to go make a bunch of
arbitrary changes and risk a bunch of regressions because someone doesn't
like a keyword. This is a source-breaking change, and we need to stop
making source-breaking changes unless they're absolutely necessary, and
this is far from absolutely necessary.

Accepting this proposal would waste hundreds of person-hours of work and
cause even more confusion than it's trying to prevent by causing tons of
existing online documentation, tutorials and answered questions to be
rendered incorrect.

I vote "No".

-Carl

···

--
Carl Brown
Swift@IBM
Carl.Brown1@IBM.com (Work)
CarlB@POBox.com (Home)


(Ian Keen) #10

In terms of black and white, approve or don't approve - I agree with Matt, thumbs down on this one from me too.

For what it's worth while I also use fileprivate a lot I dislike the concept... I think pairing scope to something physical like a file is weird - but I also believe it is a symptom of a flaw in the tooling.

If Xcode supported module/framework based development as easily as IDEs like visual studio then fileprivate would never have been needed and internal scope would actually serve a purpose. We would have 'internal' types that can live in their own files but would be invisible to the consumer of the module/framework.

_That_ would be my hope for access modifiers going forward, but unless Xcode is open sourced I fear that we have to make language compromises like fileprivate which as essentially a crutch imo.

Ian Keen.

···

I would like to separately concur with (most of) Matt's excellent review.He identifies what I think the core issues here, which are
People code in different styles.A scoped keyword is more useful in some styles and less useful in others, and this debate is in many ways a proxy war about programming style.
Most of the "solutions" proposed boil down to telling private users to adopt a different programming style.Instead we should be making Swift a great language for a *wider* diversity of programming styles as it expands to new platforms and solves new problems.
The complexity argument seems weak or even absent.It consists largely of the informal observation that 3 keywords are better than 4, which may "feel true" but does not have the research behind it of a Goto Considered Harmful™.Instead, most of the research on usage and impact are coming from those trying to keep it, which does not seem like their burden to meet.
On March 23, 2017 at 1:22:49 AM, Matt Gallagher via swift-evolution (swift-evolution at swift.org) wrote:

> What is your evaluation of the proposal?
I disagree with this proposal. It removes functionality that I actively use.

This proposal aims to revert SE-0025 without really addressing the aims of that proposal, merely dismissing the result as "actively harmful" without defining what that means. SE-0159 raises the complaint that "private" is syntactically more natural default while "fileprivate" is a more useful default. On this point, I agree but the proposal is not about mere renaming.

The other discussion in the proposal is to ask the questions:

1. is that distinction between private and fileprivate actively used by the larger community of Swift developers

2. if it were used pervasively, would it be worth the cognitive load and complexity of keeping two very similar access levels in the language?

Fair questions but despite the proposal claiming "This proposal argues that answer to both questions is no", the proposal offers no *arguments* for the answers, it merely states a position.

For this reason, I feel the proposal is unreasonably dismissive of the aims of SE-0025.

Frankly, both these questions have subjective answers based on how programmers tend to design their programs. I personally like to build functionality using lots of very tiny types (many just 4 or 5 lines long), therefore, I frequently put multiple types in the same file (they're part of the same functionality, even if they're not part of the same type). However, I want to have actual interfaces and implementation hiding between them otherwise there's always the possibility of accidentally abusing the interface to each type. An access modifier narrower than the file, like the current scoped "private", is the *only* way to achieve this.

Reverting SE-0025 means the only way to have enforced interfaces between types is to place them in separate files. This is counterproductive for tiny types that form a single conceptual entity. Separate files also requires whole-program optimization for optimal performance.

The only conclusion I can make is that programmers in favor of this proposal simply don't program this way. However, I find it insulting that this proposal is essentially saying: your way of designing and structuring programs is wrong; you must use big monolithic types in their own files and endure reduced compilation (whole-program optimization) or runtime performance (no inlining between files with whole-program off).

I can't help but feel that this proposal is really misdirected frustration. Programmers who don't use clusters of tiny types in a single file shouldn't care about the existence of a scoped access modifier because it shouldn't affect them – they should use file access modifiers and be done. Yet apparently, it is file access modifier advocates pushing this proposal.

It really seems like the existence of a scoped access modifier is taking the blame for people's frustration that the simpler keyword ("private") is a less good default than the clunky keyword ("fileprivate"). I personally agree that the behavior or "fileprivate" is probably a better default so I understand the desire to give "private" back that meaning again. However, I don't want to lose a scoped access modifier because it is *useful* (for reasons of both project structure and compilation or runtime performance).

So... thumbs down from me. However, if someone wants to rename fileprivate ->private and rename private ->scope (or something) I'd be more supportive.

Regards,
Matt Gallagher.


(Ian Keen) #11

I missed the other code based modules conversation floating around... this would also be a much better solution imo - dropping fileprivate and having modules with open/public/internal/private seems like it would cover everything one might need without being bound to something like a physical file..

/shrug

···

In terms of black and white, approve or don't approve - I agree with Matt, thumbs down on this one from me too.

For what it's worth while I also use fileprivate a lot I dislike the concept... I think pairing scope to something physical like a file is weird - but I also believe it is a symptom of a flaw in the tooling.

If Xcode supported module/framework based development as easily as IDEs like visual studio then fileprivate would never have been needed and internal scope would actually serve a purpose. We would have 'internal' types that can live in their own files but would be invisible to the consumer of the module/framework.

_That_ would be my hope for access modifiers going forward, but unless Xcode is open sourced I fear that we have to make language compromises like fileprivate which as essentially a crutch imo.

Ian Keen.