[Review] SE-0025 Scoped Access Level


(Douglas Gregor) #1

Hello Swift community,

The review of SE-0025 “Scoped Access Level" begins now and runs through March 3, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.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
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/0025-scoped-access-level.md
Reply text

Other replies
<https://github.com/apple/swift-evolution#what-goes-into-a-review-1>What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and 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?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager


#2

What is your evaluation of the proposal?

I don't think it makes its case well. The alternatives it lists are sufficient and, if anything, mentioning them makes their case equally well (or better).

The suggestion that the current behavior "forces a one class per file structure" is misleading. While it may require a careful API designer to use one file to scope truly private behavior, they are free to implement other parts of this class/structure/enumeration (and others) elsewhere.

The one limitation of splitting logic over many files (a limitation the proposal does not mention) is that stored properties can only be defined in the initial definition of a class/structure. I can see a separate case (and proposal) to be made for allowing stored properties to be defined in extensions as long as the class/structure definition exists in the same module. I also remember reading a lukewarm discussion here around removing this limitation.

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

No. The problems it attempts to address can already be solved with the existing levels of access control. It also feels incongruous alongside them and would make Swift's design more confusing and complex.

I believe that for those that want it, this kind of scoping could be enforced using a linter.

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

No. Swift has lately been removing, not adding, complexity. The bar for new language features is being set rather high, and this proposal in its current state is not convincing enough.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I don't know of any other languages that have 4 levels of access control. I have used languages that have more traditional "protected" and "private" inheritance-based access control (the latter of which is similar to that suggested in this proposal). I believe the Swift team carefully considered prior art and thoughtfully designed the current setup (as described in https://github.com/apple/swift/blob/master/docs/AccessControl.rst).

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I read through the proposal and have thought extensively about the existing design.

···

--
Stephen


#3

One good thing which is not fully highlighted in the proposal is when using nested classes, one can protect the guts of the inner class from the containing class. For completeness the local keyword would have to be useable to create local setter as well.

class outer {
    class counter {
        local(set) var count: Int = 0 // Cannot set from outer
        func incr() { count += 1 }
    }
    var data = counter()
    func somework() { data.incr() }
}

Dany

···

Le 26 févr. 2016 à 14:05, Douglas Gregor via swift-evolution <swift-evolution@swift.org> a écrit :

The review of SE-0025 “Scoped Access Level" begins now and runs through March 3, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md


(David Waite) #4

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md
What is your evaluation of the proposal?

-1

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

After what seemed like endless discussion, I remain unconvinced that its actual stated motivation justifies its inclusion.

The justification appears to be that there needs to be some way to protect portions of a single source file from one another. A better approach here from my personal experience is just to require developers to have responsibility for understanding the functioning of all the code in a file before making changes, and to structure your code so that you use multiple files to represent different concepts.

The example in the detailed design shows an extension in the same file where counter and advanceCount are not visible to an extension. However, there is nothing to prevent a developer who wishes to use advanceCount to implement a private incrementTwice from putting their code within the class itself, rather than in an extension - literally a difference in insertion point of the same code, and providing the same external behavior.

One use I can partially agree with is that a local scope would allow playground users to more easily experiment with scopes. However, it does not make sense to teach access control with playgrounds unless one is able to show the usage of other scopes - and adding another access control level which students need to keep in their head seems a counterintuitive approach to teaching.

I believe this proposal is mostly motivated by the impedance mismatch between ‘private’ in other languages meaning that access is restricted to a type implementation body or similar, while ‘private’ in swift limits access to the current file. While I can understand someone preferring the system they are more familiar with (especially in the face of private requiring a particular code structure), I don’t believe the additional access model complexity is justified in supporting both.

I expect developers would gravitate toward using one or the other. Other aspects of Swift currently push for file-level access control semantics, such as implementing Equatable for a type based on its internal state. As such, I don’t know if “local” would be used even in contexts where it might be a slightly better fit - developers will already be required to use file-level access control to implement other things.

I will second Joseph Lord’s inquiry for anyone code which has had negative impacts to its safety by the lack of this feature - specifically interested in cases where the file based access control was insufficient, rather than cases where file based access control was not attempted to be used.

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

I don’t know of any v3 goals this aligns with.

My understanding is that this comes about from a simple idea - someone wants to have objects which have some protection of their API from the outside world, and to limit the interface between those objects from exposing internal implementation details in order to maintain invariance. Today, this is done by making the interface between objects internal, and putting the objects in separate files so that they can have private implementation details. Where this can fall down is when you want the API between objects to not be exposed to other members of a module.

Therefore, I wonder if an alternate direction for Swift evolution would be to promote the creation of many smaller modules vs a few large frameworks. Approaches which come to mind for this would be to have submodules as part of a single framework, or otherwise optimize the language, packaging, and/or runtime platform to promote the idea that ‘micro frameworks’ containing less than a half dozen types and as little as 100 lines of code are appropriate and will not have a deployment or runtime impact.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Most of my experience implementing frameworks has been on top of Java, C#, C++, and Ruby.

The existing public/internal/private system I believe compares favorably with these languages. I don’t believe any of these languages have a file-level limit of object accessibility, instead having ‘private’ be similar to the local lexical scope defined here. Rules about exposure of private methods when you have inner/outer types vary, as do accessibility of private methods through type introspection. As stated above, I suspect some motivation behind this proposal are the difference in ‘private’ as defined in other languages vs in Swift - but I don’t believe both are justified in being present in the language.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Significant participation in discussion before proposal.

-DW


(Nate Cook) #5

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md
I support the proposed change to add a locally scoped access level. After following the original discussion and re-reading the proposal, I'm confident that this additional scope level would support the design decisions already present in Swift and help us write safer, simpler code.

Adding the local access level would essentially let extensions act as local scope blocks for a type's or protocol's methods. Many methods are made simpler by extracting an encapsulated chunk into a separate function, but these extracted bits have preconditions and requirements that would be excessive to check again.

For example, one algorithm for rotating a collection uses an "unguarded" rotate as one of its steps, which is optimized to rotate a portion of the collection without bothering to check the inputs. It makes sense to extract this bit of the full rotation algorithm into a separate function, but it's unsafe to call unless very specific requirements are met that are unlikely outside the expected context. Being able to specify a local access level for the unguarded rotation would make this safer.

While an additional access level would certainly make the system more complicated, the proposed "local" access level fits into the same framework as the three existing tiers. Unlike adding an inheritance-based level like "protected", this continues the practice of access level as defined by proximity. Types and methods are available at the global, module, or file level; this proposal would extend that down to the scope level for even finer control over the same axis of specificity.

In sum, this proposal gets my vote and I'm certain I would use the feature if added to Swift.

Nate


(Drew Crawford) #6

What is your evaluation of the proposal?

+0.9

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

Yes. Let me defend that a little, since that seems to be the angle of criticism for this proposal.

Some propose that convention is good enough. But the difference in safety between "convention" and "compile error" is stark.

Threading is one especially pernicious case. If I have an ivar that is only safe for access from one thread, I *need* compiler enforcement. I *need* a guarantee that this ivar is only accessed through public interface methods that can be audited to be threadsafe. Simply a doccomment that says "bad programmer, don't do it" is not enough.

This is not even a matter of "artistic choice" of whether or not I want to follow "one file per class". I can achieve thread safety with "private" ivars and "one file per class", but if my class is UITableViewCellContentView (which is an implementation detail that should be hidden even to most of UIKit) I am now forced to expose that implementation detail to my entire team.

This places me in the unconscionable situation of choosing between whether I have thread safety or encapsulation, between whether my coworker will accidentally create a threading bug or accidentally use a class they ought not to use and I am unable to appropriately hide.

ObjC has a solution to this problem: the "Foo-private.h". Obviously I think that is not the right solution for Swift. But to say it is not a significant problem is to be unfamiliar with the complexities of large ObjC codebases.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Personally, the solution I would prefer is Rust's "use" / "pub use" system. (For an explanation on this accessible to Swift programmers, see here <http://faq.sealedabstract.com/rust/#visibility>.) The key difference is that while Swift has a flat namespace for each module, in Rust, modules are recursively composeable. So Rust's UIKit framework would consist of multiple "components", such as a UITableView component (with e.g. UITableView, UITableViewController, UITableViewCell, UITableViewCellContentView, etc.), UIText component (UITextField/UITextArea), UINotification component (UILocalNotification, UIUserNotificationAction, UIUserMutableNotificationAction), etc., where each component has identifiers that are private to the class, identifiers that are shared with only the component, identifiers that are internal to all of UIKit, and identifiers that are public to the application developer.

The advantage of the Rust system is that it can achieve in two access keywords what Swift achieves in four. However, a change like that would be more controversial than the present proposal. I support some progress on improving access modifiers, even if this is not my ideal solution.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've followed this from the earliest discussions. I've rethought my position somewhat in response to the growing uncertainty about dropping the NS prefix, which I think exposes some very real problems with visibility in Swift.

As that situation has developed, I no longer believe this proposal goes far enough. But it does go somewhere, and we should not stay where we are.

···

On Feb 26, 2016, at 1:05 PM, Douglas Gregor <dgregor@apple.com> wrote:

Hello Swift community,

The review of SE-0025 “Scoped Access Level" begins now and runs through March 3, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.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
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/0025-scoped-access-level.md
Reply text

Other replies
<https://github.com/apple/swift-evolution#what-goes-into-a-review-1>What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and 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?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager

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


(Joseph Lord) #7

-0.1
There is nothing wrong with this proposal but I just don't see the value over private (plus a little doc comment if absolutely necessary).

Downside is more language to learn / encounter and complexity to maintain.

I've read the proposal but not the preceding discussion.

Joseph

···

On Feb 26, 2016, at 7:05 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

The review of SE-0025 “Scoped Access Level" begins now and runs through March 3, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md


(Nicola Salmoria) #8

What is your evaluation of the proposal?

+1

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

I think it addresses a significant omission in the language which deserves to be filled.

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

I think it does.

The emerging pattern in Swift development is to keep type definitions short and focused, and then add additional functionality with extensions.

Extensions therefore become the basic blocks of code in a type. Sometimes they need to contain implementation details which are only relevant to the specific functionality implemented in the extension, and don’t need to bubble up to the surface of the whole type.

Normally when we work in a block between curly braces, everything we declare is local.
When we work between the curly braces of an extension block, however, we don’t have any way to achieve the same behaviour: everything we declare needs to be shared at a minimum with the whole file.

Adding the ‘local’ access level merely reinstates what we take for granted in other parts of the code. It means that as a code maintainer, when I see a ‘local’ entity in an extension I only need to check how it is used inside that extension, rather than in the whole file.

This will become even more important if in the future it will be possible to declare properties inside extensions.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I don’t have experience with any other language that uses extensions in such a significant way.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

A quick reading.

···


Nicola


(plx) #9

What is your evaluation of the proposal?

Short form: the problem addressed is very real and IMHO very significant; the proposed solution is *useful* but on reflection seems to illustrate this isn’t a problem that can be *entirely* addressed just by adding another scope (or scope(s)). I think I agree with what I think Drew has been saying that the visibility model itself may be not quite ideal (it isn’t broken or anything).

I’m also a little unsure how useful `local` will be in the context of the rest of the language at this time; it seems like to really come into its own we’d also want e.g. to be able to split up the definition of a type across multiple extensions within the same module.

Longer form: within Swift’s existing access-control approach, if you want to keep things private—as opposed to merely internal—it’s easy to wind up with numerous closely-related types, all living in the same file. The only sensible visibility for most of the aspects of most of the types is `private`, but because these are all living in the same file we don’t actually get any effective "cross-type” access-protection within that file.

So e.g. for a custom type implementing `CollectionType`, you can have the type itself, an associated index type, and perhaps also an associated generator type; if instead of “is-a `CollectionType`” you instead opt for “has-multiple `CollectionType` views”, then you can wind up with the base type + 2-3 closely-related types per such view (the collection type, its index, and perhaps also the generator).

The standard-library `String` is an example, where it’s not itself a collection but has 4 “views”, each of which defines an index, and one of which also adds a custom generator.

I don’t have a short example I can share, but I can describe one: at one point I wrote an “accelerated 2D point array”, which was effectively an array of `CGPoint`, but in struct-of-arrays style (e.g. separate arrays of `x` and `y` coordinates). The tricky part is it had a delicate internal state, since the actual storage looked like this (many details elided here) :

@implementation PointArray {
  float *_bufferA;
  float *_bufferB;
  float *_bufferC;
}

@property(nonatomic, assign) PointArrayState state;

@end

…wherein *which* buffer was for `x` or `y` varied over time (and was tracked via that `state` field). The reason for this design is many of the array-level operations were implemented using functions from Accelerate, which in turn often benefit from being done “out-of-place” (and thus e.g. to translate each point by dx,dy, if you started out with `bufferA` having the x-coordinates and `bufferB` having the y-coordinates, you might wind up with `bufferC` holding the updated x-coordinates and `bufferA` holding the updated y-coordinates, along with `state` updated to reflect that updated arrangement).

This is code that would arguably benefit from being migrated to Swift at some point. As it is in Objective-C, it’s implemented as part of a larger family of classes, and it’s easy to tightly control visibility: there’s public headers, there’s private headers imported by subclasses, and there’s methods defined in .m files that are difficult to call accidentally from anywhere else.

In Swift the design would change a bit — a lot of methods that in Objective-C are effectively “sort if necessary, then call this block on each point” would get migrated to “view structs” that implement `CollectionType` — but I get nervous thinking through the implementation because it seems at least a little awkward to structure the internal API in a robust way, while also having so many types all defined in the same file.

I’m not entirely sold that `local` is the ideal solution, but it’s definitely addressing an IMHO significant problem.

What does concern me about `local` is that, at present, it would seemingly force an unnatural code organization at times; the norm is typically to put each adopted protocol into its own extension, but this means that any stored fields must either be `private` — and thus not protected by `local` — or you have to implement a lot of things from within the main definition (not idiomatic).

Even then, consider a simple case like this:

public struct SomeCustomIndex<T> {
  local let position: Position
}

public func ==<T>(lhs: SomeViewIndex<T>, rhs: SomeViewIndex<T>) -> Bool {
  return lhs.position == rhs.position // oops!
}

…(in this case it’s hard to see what harm you could do with `private let position`, but it illustrates a general limit to the utility of `local` declarations).

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

Yes, VERY MUCH SO.

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

I’m not sure. I feel like there should be some better approach to visibility that solves this problem and is overall more “Swift”, but I don’t know what it is.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I think the closest analogy here is that "private + local" are trying to get Swift to the same place that, say, “protected + friend” would get it, but along a different route.

The general problem being solved is that Swift’s somewhat-unique approach to `private` is unsatisfactory for some cases—IMHO in particular for the “family of related types” scenario—and `local` adds another tool to solve it.

Although I’m well aware of the arguments against “protected (+ friend)”, I’d point out that those constructs are IMHO the *usual* approach to solving these same issues.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal, participated in original discussion, read the current discussion.


(Ondrej Barina) #10

What is your evaluation of the proposal?

-1

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

I think its not necessary.

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

Not sure.

How much effort did you put into your review? A glance, a quick
reading, or an in-depth study?

I have been following the whole discussion ago this proposal.

Ondrej Barina

···

On Fri, Feb 26, 2016 at 8:05 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Hello Swift community,

The review of SE-0025 “Scoped Access Level" begins now and runs through
March 3, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.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

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/0025-scoped-access-level.md

Reply text

Other replies

What goes into a review?

The goal of the review process is to improve the proposal under review
through constructive criticism and, eventually, determine the direction of
Swift. When writing your review, here are some questions you might want to
answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to
Swift?
Does this proposal fit well with the feel and 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?
How much effort did you put into your review? A glance, a quick reading, or
an in-depth study?

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Doug Gregor

Review Manager

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


(Taras Zakharko) #11

What is your evaluation of the proposal?

I am agains it. My rationale below.

One of Ilya’s main points is that encapsulation is a core principle of OOP and that Swift lacks tools to implement this properly. I think the terminology is somehow unlucky here. Encapsulation more universally refers to bundling of data and code that operates of that data, and this is indeed one of the things that defines OOP as a programming style. However, it seems that Ilya refers to data hiding, which often accompanies encapsulation. I believe it is important to distinguish these two concepts. Encapsulation as I use here is a particular problem-solving style while data hiding (what Ilya stresses) is a technique for enforcing program correctness. It is also not true that data hiding is a fundamental component of OOP languages, some of the popular ones don’t have any data hiding (e.g. Python).

Data hiding obviously has an important core function, which is, as I mentioned above — making sure that the program is correct, by only exposing the interface other components should have safe access to. Swift has data hiding, only the philosophy of that data hiding is a bit different from the mainstream implementations. The scope of the most restricted access is the file. If I understand the background of this design decision correctly, goal here is to allow the programmer to be as flexible as possible about what can access what but also to ‘force' them to think about their code design and code layout (by organising interrelated stuff by files). Is this an ideal decision to the problem? Certainly not — it imposes some inconveniences on the programmer and can also compromise code safety (as Illya points out). Is this a good, elegant decision? In my opinion, yes.

I can also understand Illya’s point that a local scope access might improve code safety in certain cases. What I disagree with is that these cases are prominent or problematic enough to deserve such attention. Adding new access modifiers makes the rules of the language more complicated, but I seriously doubt that a ‘local’ specifier will make programmers significantly more productive or prevent any number of serious bugs. So far, arguments presented were more of the ideological nature and while they are formally correct, I do not think that the actual end effect is as dramatic as described. In addition, I would like to point out that ‘local’ is also only an approximation — it does not solve the safety problem entirely. It merely functions as an additional safeguard agains programmer error. The actual problem can be only solved by specifying full rules what is accessible from where and under which conditions. A system like that probably won’t be practical enough for everyday programming at this point.

I also think that the comparison with ‘let/var’ as brough try Ilya is flawed — variable mutability concerns the basic design of the data structure/algorithm itself, while data hiding concerns the fragility of a data structure. I understand that the boundary between these two is very fluent, as one can portray fragility as design by encapsulating/hiding parts of the implementation. However, we are talking about actual implementations (e.g. variables, code etc. that the implementation use) rather then the abstract structure of implementations.

To sum it up: Swift already supports an elegant data hiding mechanism which IMO solves the biggest issue: components are already shielded agains incorrect EXTERNAL use. It remains prone to incorrect use in the same file. As far as I am concerned, the practical consequences of this are negligible. I have some experience with languages that do not have any data hiding whatsoever and I can’t say that I ever had any issues with messing up the private and public interfaces — neither in my own code nor in code written in collaboration with other people. In this regards do not believe that ‘local’ will add anything of value to the language, however it will make the rules more complicated.

Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?

I do not know. The problem of code safety is a fundamental one, but I am not sure that Swift has ever had the ambition to solve all of them. For me, the offered solution is good enough.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I have read the proposal, and participated in the original discussion. I can’t claim to have performed an in-depth study though.

···

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager

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


(Rudolf Adamkovič) #12

What is your evaluation of the proposal?

-1

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

In my experience, it is not.

How much effort did you put into your review? A glance, a quick
reading, or an in-depth study?

I've read the proposal and been following the surrounding discussions.

R+

···

Sent from my iPhone

On 26 Feb 2016, at 20:05, Douglas Gregor <dgregor@apple.com> wrote:

Hello Swift community,

The review of SE-0025 “Scoped Access Level" begins now and runs through March 3, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.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
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/0025-scoped-access-level.md
Reply text

Other replies
What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and 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?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager

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


(Patrick Gili) #13

What is your evaluation of the proposal?

This proposal definitely fills a gap in the access control scheme currently supported by Swift. It seems somewhat unfortunate that "private" refers to the the level of access control limiting the scope to the source file, as it seems this keyword would be better associated with the scope of access described in this proposal. I'd personally like to see "private" reassigned to the lexical scope and come up with a new keyword to describe the source file scope (e.g., maybe "file"). However, this would increase impact of the change.

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

For framework developers, the problem is significant. I'm sure application developers may have a difficult time considering this a problem.

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

Yes, I think this is fits well with the direction of Swift. I have seen some people raise the question of the proposal adding undue complexity to the language. However, I disagree with this, as the proposal adds a single keyword associated with a new scope of access control.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Many object-oriented languages support access control to members of entities. Apple went further by adding a scope of access for Swift's notion of a "module", which I have never seen any language provide. In doing so, I think they overlooked the need for the a level of access control typically described by "private". Or, Apple envisioned the one entity to a source file, like Java.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

In-depth study.

···

(Matthew Johnson) #14

What is your evaluation of the proposal?

+1. I believe I was the first person to suggest this as a direction for refining the access control feature. It fits naturally with the existing access control features, allows more refined expression of intent, and adds minimal incremental complexity to the language.

Differentiating between the intention of ‘local’ and ‘private’ access control is IMO a big win. When reading code that declares a member ‘local’, I immediately know I only need to consider how other code in the containing scope uses that member. I do not need to consider whether the member is used by other code in the same file. The increase in clarity and readability is significant.

During the discussion I looked through the code for the (at that time) current release of Alamofire to see how ‘private’ members are actually used. As it turns out, every use of `private` in that library could actually use `local` instead if it existed, with a corresponding increase in clarity and readability for anyone new to the code.

In some cases ‘private’ and ‘local’ would be equivalent because there is only one type / scope in the file anyway. However, in most cases for Alamofire they actually do communicate something different. There are a few ways this is possible:

In some cases, this is because there is a nested type involved and the `private` members are inside the nested type. They should not be visible outside the scope of the nested type.

In other cases, there are extensions of other types. These extensions add methods that are closely related to the primary type / extension involved in the file. The private members of the primary type should not be visible to the related extensions.

One other case that didn’t appear in Alamofire, but I have seen elsewhere is a case where you conform several types to the same protocol (usually a simple protocol) in the same file. In this case there may be helper methods that support the protocol implementation but should not be visible to the other implementations of the protocol that are in the same file.

None of these cases would be covered by various alternatives (related to concurrency, etc) that have been discussed in the review thread. Scoped access control stands on its on as a small but valuable addition to the language in addition to providing better short-term options for some of the cases discussed in the review until more complete and direct solutions are added to the language.

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

Yes.

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

Yes. The approach is a very natural extension of the existing access control mechanism.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

This is closer to the notion of ‘private’ than Swift’s existing ‘private’ access level. Swift’s ‘private’ solves the ‘friend’ problem much more elegantly than ‘friend’ but it leaves an expressivity gap where members are sometimes much more broadly visible within a file than is necessary.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I participated heavily in the discussion leading up to this proposal, including analysis of existing code for places where this feature would be valuable.

···

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager

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


(David Hart) #15

What is your evaluation of the proposal?

-1

I admit I was surprised by the semantics of private in Swift when I first discovered it, because I was used to private in other languages corresponding to Scoped Access Level. But I’ve not been overly bothered by it, and I’ve always kept a fairly strict one class per file anyway. I also don’t like that the proposal adds another keyword/layer of scoping. If people really wanted Scoped Access Level, I would have suggested modifying the meaning of private to correspond to Scoped Access Level and not add another keyword like this proposal.

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

I’d say no.

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

I don’t find it worthwhile enough to warrant adding another scoping level and confusing newcomers.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Yes, all the other languages I have used have had Scoped Access Level, but I don’t mind Swift’s current file access level.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

A thorough read.


(Rob Mayoff) #16

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md

   - What is your evaluation of the proposal?

I am very in favor of an access control modifier with the effect described

in the proposal. The proposal addresses a shortcoming of the Swift language
which I have felt acutely many times. I am not particularly attached to the
specific word “local” as the modifier.

   - Is the problem being addressed significant enough to warrant a
   change to Swift?

Yes.

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

Yes. It conveys an important intent to the compiler for enforcement with

minimal impact to the style and structure of the language.

There are other features that I hope to someday see in Swift that would
sometimes replace the need for this (e.g. nested modules). Even so, I think
there will always be cases where this level of access control conveys
useful information.

   - If you have used other languages or libraries with a similar
   feature, how do you feel that this proposal compares to those?

Of the languages I've used heavily, C++, Java, and Scala have a similar

level of access control. Scala has the finest granularity of access control
amongst the languages I've used. Scala has more access control granularity
than I've ever needed, but Swift has less than I've wanted. This proposal
improves Swift without going overboard.

   - How much effort did you put into your review? A glance, a quick
   reading, or an in-depth study?

I read the proposal carefully. I also followed the original discussion

closely and participated in it.


(Brent Royal-Gordon) #17

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md

  • What is your evaluation of the proposal?

I don't think it's a good idea.

I think the source of our disagreement is expressed in this paragraph from the proposal:

It forces a one class per file structure, which is very limiting. Putting related APIs and/or related implementations in the same file helps ensure consistency and reduces the time to find a particular API or implementation. This does not mean that the classes in the same file need to share otherwise hidden APIs, but there is no way to express it with the current access levels.

This reflects a view that grouping APIs into files is a purely stylistic choice. You can move APIs around freely and organize them however you like. If Swift gets in the way of your preferred arrangement, Swift should be changed to allow it. The most important thing is that you be free to express yourself artistically through the medium of the file system.

I believe that view is mistaken. Swift has a very opinionated view of how code should be organized into files; they are as semantically meaningful as declaration blocks.

The purpose of a file is to implement one concern—essentially, one logical piece of the module's functionality with its own self-contained implementation details. A concern is not necessarily fully represented by a single type; a type may include several concerns, and several types may implement one concern. (It's not a coincidence that a file can contain several types and a type can be split across several files.) The precise boundaries of a concern are a little nebulous, especially when you build convenience APIs which don't depend on anything private, but it's usually roughly clear what they are.

When you want to use `local`, that usually means you're not organizing your code the way Swift thinks you should. It's no wonder Swift seems to not be expressive enough: You're fighting the language.

Now, there are two exceptions to this general rule, but I think they're both best handled in other ways.

The first: Sometimes Swift will not allow you to move certain things to separate files; for instance, only one file can declare stored properties on a type, and so stored properties must either be made more visible than they should be, or several concerns must be mixed into a single file. I think this is best handled by allowing extensions to declare stored properties and other such one-file-only constructs, rather than by complicating access control.

The second: Sometimes a particular concern has an especially complicated, self-contained "sub-concern" which has implementation details of its own. You would like to keep the sub-concerns implementation details private from the containing concern, but the sub-concern is *itself* an implementation detail of the containing concern, so you *also* want to keep the sub-concern private from other, unrelated concerns. In these cases, some sort of more nuanced access control would be better—but even then, I don't think `local` is actually a very good way to do it.

There's nothing about a declaration block that makes it a natural choice for scoping declarations. `local` hides the declaration from containing and sibling declaration blocks and exposes it to nested declaration blocks. But if concerns often transcend type boundaries, surely sub-concerns do as well, so `local` will often be either too limiting or not limiting enough.

To properly handle this problem, we would be better off coming up with some way to limit the scope of `internal` to only particular files which need to interface with that file's concern. `internal` would expose the API to your file's "clients"—by default all files in the module, but potentially narrowed down to a particular subset—while `private` would remain as something truly limited to a single file.

However, that approach is rather complicated, bordering on the horror of C++ `friend` declarations. Ultimately, I just don't think it's too large of a burden to say, "You have a three-level namespace, and anything that crosses files goes into `internal`; if something in `internal` is only meant to be used in a particular file, show some discipline."

  • Is the problem being addressed significant enough to warrant a change to Swift?

As I often say, the problem is arguably significant enough, but I don't think the solution is the right one.

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

I don't think so. Swift has strong, opinionated ideas about how code should be organized; this proposal doesn't follow that pattern.

  • 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 languages with file-based scoping, and languages with arbitrary lexical scoping, but not languages with both.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

In addition to reading the present proposal, I also participated fairly extensively in discussions about it and read previously-posted reviews.

···

--
Brent Royal-Gordon
Architechies


(David Owens II) #18

What is your evaluation of the proposal?

-1. I disagree with the starting motivation points, so it's hard to really see the value in the rest of the arguments.

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

No.

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

No. Swift's access modifier control is about code unit access levels. This proposal breaks this conceptual model. Now instead of thinking of publicly exposed APIs, APIs using only within the context of the module, and APIs local to the file, I now need to parse semantic scopes to understand where a piece of code can be used.

Basically Swift's model is:
  - public exports
  - internal exports
  - no exports

This proposal doesn't fit anywhere in that model.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Yes, this basically what private is other languages. However, traditionally "private scope" implementations have severe weaknesses in the ability to expose the implementation details only to helper code within the same file. Creating local re-invents part of that.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've read the review and followed much of the conversation, including participating in the previous thread on this topic.


(Jim Kubicek) #19

What is your evaluation of the proposal?

+1

This proposal addresses a pain point I encounter daily. Currently there is no (good) way to limit extension methods to use only within the containing extension. I think the added clarity of a compiler-enforced access to “local” extension methods will be a solid win. In addition, it’s possible for code completion to no longer suggest the inaccessible methods.

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

Yes, especially because this change can largely be ignored by developers new to Swift and only brought into play when needed.

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

Certainly. “Local” feels like a natural extension of the existing access level keywords.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal and the commentary in this thread.


(Adrian Kashivskyy) #20

What is your evaluation of the proposal?

Neutral. While I agree that scoped access levels can be useful in some cases, I don't see much long-term profits, especially when using a "protocol conformance in an extension" style:

struct Foo {
  private func doSomethingInternal()
}

extension Foo: Barable {
  func bar() {
    doSomethingInternal()
  }
}

The above would not be possible to achieve with scoped access levels.

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

I don't think so. File access level does the job well for me.

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

Yes and no. Yes, because it a

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Yes, Ruby, PHP, C++. In those languages, there are no file access levels and so the scoped access levels are the only ones which allow to hide the implementation details from the outside world. In Swift, however, file access level allows us to do the same with additional bonus – we can use those `private` members in extensions.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Pozdrawiam – Regards,
Adrian Kashivskyy

···

Wiadomość napisana przez Douglas Gregor via swift-evolution <swift-evolution@swift.org> w dniu 26.02.2016, o godz. 20:05:

Hello Swift community,

The review of SE-0025 “Scoped Access Level" begins now and runs through March 3, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.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
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/0025-scoped-access-level.md
Reply text

Other replies
<https://github.com/apple/swift-evolution#what-goes-into-a-review-1>What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and 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?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

-Doug Gregor

Review Manager

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