Why does private allow access from nested classes?

According to the documentation:

Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.

In the following example, an instance of Bar is able to access Foo's private instance variable baz. This seems to be in line with the documentation above: the nesting (the nested class being Foo.Bar) provides Bar with access to baz.

class Foo {
    private var baz = true

    class Bar {
        func doSomething() {
            let foo = Foo()
            foo.baz = true
        }
    }
}

This also means that any instance of a class can access the private variables of other instances of Self that it has created:

class Foo {
    private var baz = true
    func doSomething() {
        let foo = Foo()
        foo.baz = true
    }
}

This is surprising to me!

Does anyone have any insight as to why this decision was made?

Hello @tehpsy,

You are seeing the effects of SE-0025 and its addendum SE-0169. Those proposals and linked discussion threads can answer some of your questions. Be ready for looooong discussions: this has been one of the most discussed area of the language. The topic is actually considered closed for good by now (you can suggest changes, but they have 99.99% chances of being ignored unless you provide a more-than-compelling rationale).

Your surprise makes me think that you expected private to work as in Ruby? Maybe check the Access Control chapter of the Swift Book for an accurate reference.

1 Like

Try to put that doSomething() in an extension. Then try to put that extension into a separate file.. Swift access control modifiers gravitate towards "per file access" model. The great contributor to that decision is ability to extend types (and put those extensions into separate files). I don't know how other languages that have the concept of type extensions cope with this issue, perhaps there's something to take from there, but it is highly unlikely swift current access modifiers model will change.

Swift's access scopes are deliberately lexical: this pre-dates Swift Evolution. This allows the sort of access that you describe where desired, and where not desired, you can lexically separate the code (e.g., put it in a different file).

2 Likes

Thank you all for your helpful comments!

1 Like