[Pitch] Access Level must follow as Guiding Principle

Sometimes the access level doesn't follow the guiding principle, so I did Pull-Request the swift-evolution on Github, and if you're curious about this, I'd like you to take a look.

Please tell me if there is anything wrong. Thank you.

It's kinda hard to understand what exactly you think is wrong with the book. But in general I think you misunderstand a bit how access levels work.
Let's take a look at your Example 3.

private class PrivateClass {
    private var epp = 0
    var ipp = 0
}

PrivateClass().epp
PrivateClass().ipp

Suppose the class is defined at the top level of the file.

  • PrivateClass has private access modifier, so it will be visible within the file.
  • epp property has private access modifier, so it will be visible within the scope of the class, but not outside of it.
  • ipp property has no access modifier, so its implicitly internal. As it's defined in a private class, you can't refer to it from outside of the file, because the class itself isn't visibile. But you can do it from the scope of the file.

So the compiler behaviour is correct.

PS. Also, it seems the Swift Book is not subject for the evolution process. https://github.com/apple/swift-evolution/blob/main/process.md#scope

4 Likes

Thanks for your replying.

But I wanna know why ipp doesn't have any error by compiler. You told me ipp is implicitly internal. I already guessed that ipp run like internal not private.

In the document for Access Level says below that.
(Documentation)

If you define a type’s access level as private or file private, the default access level of its members will also be private or file private.

And they show some example like that.

private class SomePrivateClass {                // explicitly private class
    func somePrivateMethod() {}                  // implicitly private class member
}

Also, I know about that if I declare access modifier such as public or internal then the default access level of the type’s members will be internal.

If I missed something plz tell me. Thank you.

PS. I'll check Swift Book is not subject for the evolution process.

2 Likes

private means that it is only available in the local scope. So when you define a private type at the file level, like this:

private class SomePrivateClass { // explicitly private class
    func somePrivateMethod() {} // implicitly private class member
}

Then the class is accessible to the whole file. That's why you're able to call the method. Whereas if the method is marked private than it can only be accessed in the class definition and in class extensions.

1 Like

This subtlety catches people up quite often. It's confused me in the past. It makes perfect sense as a rule, it's just not documented to full precision. e.g. the docs could be clearer if they said something like:

private class PrivateClass { // Private to the enclosing scope
                             // e.g. the file, if declared at the top level.
    private var epp = 0 // Private to this class.
    var ipp = 0 // Inherits the overall access level of the class,
                // so private to the enclosing scope *of the class*
                // (i.e. still accessible throughout the file,
                //  if the class is declared at the top level).
}

Of course, an actual doc writer would find a more concise phrasing, but you get the idea.

4 Likes

I think @shlim raised a valid question. Not only the Swift access control doc lacks the information explaining why the following code works, but also it apparently has incorrect information.

private class PrivateClass {
    var x = 0
}

PrivateClass().x

In "Custom Types" section of the doc, it says

The access control level of a type also affects the default access level of that type’s members (its properties, methods, initializers, and subscripts). If you define a type’s access level as private or file private, the default access level of its members will also be private or file private.

Then it gives this example:

private class SomePrivateClass {  // explicitly private class
    func somePrivateMethod() {}   // implicitly private class member
}

With the above information, it's impossible for one to understand why the example code works, because PrivateClass().x is neither in the declaration of PrivateClass nor its extension (that's the definition of private access in the Swift doc).

I find the answer in SE-0025. It has a dedicated section explaining the behavior.

When a type is defined with the private access modifier, things become a little more complicated. Of course the type itself is visible only within the lexical scope it is defined in, but what about members of the type?

If the members of a private type are themselves considered private, it is very clear that they cannot be used outside of the type itself. However, it is also not currently permitted for a member to have an access level greater than its enclosing type. This restriction produces a conundrum: the type can be referenced within its enclosing lexical scope, but none of its members can.

Ignoring formal concerns, the most likely expected behavior is that members not explicitly marked private are permitted to be accessed within the enclosing scope of the private type.

To achieve this goal, we relax a few of the existing rules:

  • The default level of access control anywhere is internal.
    ...

That not only explains why the example code works, but also indicates the description in the Swift doc I quoted above is incorrect, because they conflict with the following design in SE-0025 (emphasis mine):

The default level of access control anywhere is internal.

I believe the Swift doc must have gone through many iterations of review by people who know the ins and outs of the language. Could it be that the doc was written before SE-0025 was implemented? Or the design in SE0025 was changed later? but I don't find SE doc for that change. Also, if the current implementation really worked in the way described by the Swift doc, I don't think the example code could work. So I suspect this is a bug in Swift doc. I'm copying to people in the document work group for their opinion. CC @franklin

2 Likes