[swift-evolution] Type-based ‘private’ access within a file

Brent Royal-Gordon brent at architechies.com
Mon Apr 3 18:55:55 CDT 2017


> On Apr 3, 2017, at 3:07 PM, David Hart <david at hartbit.com> wrote:
> 
>> On 3 Apr 2017, at 23:55, Brent Royal-Gordon <brent at architechies.com <mailto:brent at architechies.com>> wrote:
>> 
>> 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).

Sure, but extensions are precisely the reason why `private` is complicated in Swift. That's a bit like saying "we should use integer string indices because they work just fine in languages without good Unicode support".

> And it would still allow many uses of private, like Drew Crawford’s ThreadsafeWrapper example from the 23rd of March.

That's great, but the goal is not "Don't break Drew Crawford's one example from the review thread". The goal is "provide a set of access levels which provide appropriate degrees of protection for many use cases".

To talk about concrete examples, here's a SortedDictionary type I wrote: <https://gist.github.com/brentdax/106a6a80b745bd25406ede7a6becfa30> It has a pair of `private` properties called `_keys` and `_values`, whose indices have to stay in sync. To enforce that invariant, it uses `private` to ensure that only a few primitive members have direct access to the properties in question. Changing `private` to be file-and-type-based would render that protection useless.

Now, I could redesign this to wrap `_keys` and `_values` plus the privileged members in a separate type, but that type would be wholly artificial; it would have no meaning of its own, and would exist solely to get a certain access control behavior. One effect would be that I'd have to write the `startIndex` and `endIndex` properties twice, increasing boilerplate for no good reason. This is one of those places where scoped `private` really *is* just what I want, and type-and-file `private` really, really isn't.

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

I look at this the opposite way: If you do not sometimes have to switch a `private` to `fileprivate` or vice versa, then `private` and `fileprivate` are basically synonyms and we ought to accept SE-0159 just to simplify the language. If, in your chosen coding style, `private` and `fileprivate` are almost always synonyms, then it's a distinction without a difference, cognitive load that doesn't bring any benefit.

IMHO, the "I have to switch back and forth" argument is a good reason not to have two different sub-file access levels because it suggests that the distinction being made is too fine. It's not a good reason to loosen one of the sub-file access levels so it looks more like the other, which only makes the distinction even finer.

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

And I'm pushing back on that, because there is no technical reason I can discern why we can't go from scoped `private` to file-and-type `private`. Perhaps there's a social reason—the core team won't want to change access control semantics once Swift is more stable and popular, or they think this topic is a giant ongoing distraction and want to settle it once and for all so they can declare it off-limits forever—but I don't think we should make a speculative change to yet a third design right before we do that.

Honestly, I think it's becoming increasingly clear that no access control design will ever satisfy everybody. So let's lock down the unsatisfactory design we know, rather than the unsatisfactory design we don't.

-- 
Brent Royal-Gordon
Architechies

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170403/0e615365/attachment.html>


More information about the swift-evolution mailing list