[swift-evolution] [Review] SE-0159: Fix Private Access Levels

Brent Royal-Gordon brent at architechies.com
Sun Mar 26 20:44:37 CDT 2017

> On Mar 26, 2017, at 10:43 AM, Matthew Johnson via swift-evolution <swift-evolution at swift.org> wrote:
> On Mar 26, 2017, at 10:43 AM, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
>> This reaches the crux of the issue, doesn't it? The Swift 2 design for access modifiers does exactly what you reject: that design is based on the premise that it is wise for file organization to follow encapsulation.
> It's always a gamble speculating about the premise of someone else's design.  That said, if I had to guess I would imagine maybe it had as much to do with the legacy of C-family languages and header files as anything else.

I've seen people say this several times in access control threads, but personally, I don't think the use of files for access control is a "legacy" or a coincidence. I think it's a pretty smart move.

By its nature, the `internal` scope is already defined by files: There is a certain set of files which are compiled together to form the module, and those files all see the same `internal` scope. Unless we entirely abandon the idea of Swift as a fully textual language and move to a FoxPro-style system where code is stored in a structured database, this will always be true in Swift. I have a hard time imagining an environment for writing Swift code where there *aren't* files or some equivalent named-chunk-of-arbitrary-code unit of organization like the "pages" in a playground.

Using files to scope `private` is thus a natural extension of the `internal` scope's rules (one group of files defines the `internal` scope; one single file defines the `private` scope). It also happens to fit well with typical programmer behavior. Organizing your code into files by concern is generally considered a best practice, but files do not carry any other semantic meaning: there's nothing (else) in the language that forces you to put a given declaration in one file or another. So with file-based `private`, there are only two reasons to care about which file a piece of code is in—`private` access and subjective code organization—and these two things are usually aligned.

This point is actually implicitly acknowledged by, for instance, the submodule proposal Jonathan Hull put forth upthread, where each file is implicitly its own submodule if not declared to be part of a different one. Files aren't always the right encapsulation boundary, but they often are.

What *can't* file-based organization do, but explicit or implicit scope boundaries can? Well, they can't nest. But as I've previously argued, limiting access to the confines of a nested scope is often problematic because you can only address the current scope, not a surrounding scope; thus, sharing even one level up requires you to "overshare" with the entire file or even (if there's no `fileprivate`) the entire module. Unless you start building `friend`-like features, of course, but I believe John McCall already discussed why that's a bad idea:

> access control is never going to be sufficiently expressive to express constraints like "this method can only be called from this other method" — we actively would not want to encourage programmers to engage in that level of pedantry, because some of them will, and they'll make themselves miserable and accomplish nothing of value, and they'll blame Swift (correctly) for implying that it was important.

We could, of course, introduce some kind of explicit declaration for private scopes. But why? Files usually match or at least approximate the desired boundaries, and when they don't already, they usually can be made to do so. Sometimes they can't, but that merely means you have to be careful. How much syntax should we really dedicate to a corner case, especially one that doesn't prevent anything from being written, but merely requires you to exercise caution?

Brent Royal-Gordon

P.S. Unless I misunderstand your meaning, I believe that this statement in your later post:

> The implicit outer scope at the file boundary is one that only exists because it was introduced in Swift 2.

Is anti-historical. The file scope is as old as `private` (and access control) in Swift, which was part of Swift 1 beta 4: <https://developer.apple.com/swift/blog/?id=5>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170326/ffe3ff41/attachment-0001.html>

More information about the swift-evolution mailing list