Here’s an early draft of the proposal. Please fire away with comments! By the 
way, how would the visibility in subclasses in the same file be handled?

https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md
 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md>

Type-based Private Access Level

Proposal: SE-XXXX 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md>
Authors: David Hart <http://github.com/hartbit>
Review Manager: TBD
Status: TBD
 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md#introduction>Introduction

This proposal extends the visibility of the private access level to all 
extensions, declarations and nested types in the same file.

 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md#motivation>Motivation

Proposal SE-0025 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/0025-scoped-access-level.md>
 introduced a lexically-scoped access level named private and renamed the 
file-based access level to fileprivate. The hope was for private to be a good 
default for restricting visibility further than the whole module and for 
fileprivate to be used in rarer occasions when that restriction needed to be 
loosened.

Unfortunately, that goal of the proposal has not been realized: Swift's 
reliance on extensions as a grouping and conformance mechanism has made 
fileprivate more necessary than expected and has caused more friction between 
private and fileprivate than intended.

As a consequence, experience with using Swift 3 has caused mixed reactions from 
the mailing list and greater Swift community, culminating in proposal SE-0159 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/0159-fix-private-access-levels.md>
 which suggested reverting the access level changes. That proposal was rejected 
to continue supporting the code written since Swift 3 which benefits from the 
distinction between private and fileprivate, but it was recognized that the 
language's lack of a good default access level more restictive than internal 
was unfortunate.

In the hopes of fulfilling the initial goal of SE-0025 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/0025-scoped-access-level.md>,
 this proposal defines the visibility of the private access level to 
extensions, declarations and nested types of the member's type in the same file 
to increase its usefulness and as a good default private access level. 
fileprivate then logically achieves its intended goal of being more rarely used 
and adheres to Swift's "progressive disclosure” philosophy.

 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md#detailed-design>Detailed
 design

The design of this proposal defines the visibility of a private member declared 
within a type X or an extension of type X to:

the declaration of X if it occurs in the same file
all extensions of X or subclasses of X in the same file
all declarations of nested types of X in the same file
all extensions of nested types of X in the same file
To illustrate the consequence of those rules, the following examples will be 
used with two files in the same module:

 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md#personswift>Person.swift

struct Person {
    let name: String
    let gender: Gender
    private let age: String

    var greeting {
        return "Hello, my name is \(name)"
    }

    init(name: String, gender: Gender, age: String) {
        self.name = name
        self.age = age
    }

    func greet() {
        // age is accessible because it is defined in the same declaration but 
secreyAge is not because it is defined
        // in a nested type so the following piece of code would generate a 
compilation error:
        // if age < gender.secrecyAge {
        // instead:
        if Gender.shouldRevealAge(self) {
            // fullGreeting is accessible because it is defined in an
            // extension of the same type in the same file
            print(fullGreeting)
        } else {
            print(greeting)
        }
    }
}

// private at the top-level scope continues to be equivalent to fileprivate
private extension Person {
    // fullGreeting is implictly private due to the extension's modifier
    var fullGreeting: String {
        // age is accessible because it is defined in the declaration of the 
extension's type in the same file
        return "Hello, my name is \(name), I'm \(age) years old."
    }
}

extension Person {
    enum Gender {
        case male
        case female

        private var secrecyAge {
            switch self {
            case .male: return 60
            case .female: return 50
            }
        }

        static func shouldRevealAge(_ person: Person) -> Bool {
            // age is accessible because we are in the declaration of a nested 
type that declared age
            return person.age < person.gender.secrecyAge
        }
    }
}

extension Gender {
    static func leakAge(of person: Person) {
        // age is accessible because we are in the extension of a nested type 
in the same file
        return person.age
    }
}
 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md#otherswift>Other.swift

extension Person : CustomStringConvertible {
    var desription: String {
        return fullGreeting
        // error: fullGreeting is not available because it is defined in 
another file
    }
}
 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md#source-compatibility>Source
 compatibility

Incoming...

 
<https://github.com/hartbit/swift-evolution/blob/type-private/proposals/XXXX-typed-based-private.md#alternatives-considered>Alternatives
 Considered

Incoming...

> On 3 Apr 2017, at 20:34, Douglas Gregor via swift-evolution 
> <[email protected]> wrote:
> 
> Hello Swift Community,
> 
> In rejecting SE-0159 
> <https://github.com/apple/swift-evolution/blob/master/proposals/0159-fix-private-access-levels.md>,
>  the core team described a potential direction we would like to investigate 
> for “private” access control that admits a limited form of type-based access 
> control within files. The core team is seeking some discussion here and a 
> motivated volunteer to put together a proposal along these lines for review 
> in the Swift 4 time-frame (i.e., very soon). To be clear, the core team it’s 
> sure this is the right direction to go… but it appears promising and we would 
> *love* to be able to settle the access-control issue.
> 
> The design, specifically, is that a “private” member declared within a type 
> “X” or an extension thereof would be accessible from:
> 
>       * An extension of “X” in the same file
>       * The definition of “X”, if it occurs in the same file
>       * A nested type (or extension thereof) of one of the above that occurs 
> in the same file
> 
> This design has a number of apparent benefits:
>       + “private” becomes the right default for “less than whole module” 
> visibility, and aligns well with Swift coding style that divides a type’s 
> definition into a number of extensions.
>       + “fileprivate” remains for existing use cases, but now it’s use it 
> more rare, which has several advantages:
>               + It fits well with the "progressive disclosure” philosophy 
> behind Swift: you can use public/internal/private for a while before 
> encountering and having to learn about “fileprivate”   (note: we thought this 
> was going to be true of SE-0025 
> <https://github.com/apple/swift-evolution/blob/master/proposals/0025-scoped-access-level.md>,
>  but we were clearly wrong)
>               + When “fileprivate” occurs, it means there’s some interesting 
> coupling between different types in the same file. That makes fileprivate a 
> useful alert to the reader rather than, potentially, something that we 
> routinely use and overlook so that we can separate implementations into 
> extensions.
>       + “private” is more closely aligned with other programming languages 
> that use type-based access control, which can help programmers just coming to 
> Swift. When they reach for “private”, they’re likely to get something similar 
> to what they expect—with a little Swift twist due to Swift’s heavy use of 
> extensions.
>       + Loosening the access restrictions on “private” is unlikely to break 
> existing code.
> 
> There are likely some drawbacks:
>       - Developers using patterns that depend on the existing 
> lexically-scoped access control of “private” may find this new interpretation 
> of “private” to be insufficiently strict
>       - Swift’s access control would go from “entirely lexical” to “partly 
> lexical and partly type-based”, which can be viewed as being more complicated
> 
> Thoughts? Volunteer?
> 
>       - Doug
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to