|
| 1 | +# Access Control |
| 2 | + |
| 3 | +The general guiding principle of Swift access control: |
| 4 | + |
| 5 | +> **No entity can be defined in terms of another entity that has a lower |
| 6 | +> access level.** |
| 7 | +
|
| 8 | +There are four levels of access: \"private\", \"fileprivate\", |
| 9 | +\"internal\", and \"public\". Private entities can only be accessed from |
| 10 | +within the lexical scope where they are defined. File-private entities |
| 11 | +can only be accessed from within the source file where they are defined. |
| 12 | +Internal entities can be accessed anywhere within the module they are |
| 13 | +defined. Public entities can be accessed from anywhere within the module |
| 14 | +and from any other context that imports the current module. |
| 15 | + |
| 16 | +The names `public` and `private` have precedent in many languages; |
| 17 | +`internal` comes from C\# and `fileprivate` from the Swift community. In |
| 18 | +the future, `public` may be used for both API and SPI, at which point we |
| 19 | +may design additional annotations to distinguish the two. |
| 20 | + |
| 21 | +By default, most entities in a source file have `internal` access. This |
| 22 | +optimizes for the most common case – a single-target application |
| 23 | +project – while not accidentally revealing entities to clients of a |
| 24 | +framework module. |
| 25 | + |
| 26 | +_**Warning**_ |
| 27 | + |
| 28 | +This document has not yet been updated for |
| 29 | +[SE-0117](https://github.com/apple/swift-evolution/blob/main/proposals/0117-non-public-subclassable-by-default.md), |
| 30 | +which adds the \"open\" level of access. |
| 31 | + |
| 32 | +## Rules |
| 33 | + |
| 34 | +Access to a particular entity is considered relative to the current |
| 35 | +*access scope.* The access scope of an entity is its immediate lexical |
| 36 | +scope (if `private`), the current file (if `fileprivate`), the current |
| 37 | +module (if `internal`), or the current program (if `public`). A |
| 38 | +reference to an entity may only be written within the entity\'s access |
| 39 | +scope. |
| 40 | + |
| 41 | +If a particular entity is not accessible, it does not appear in name |
| 42 | +lookup, unlike in C++. However, access control does not restrict access |
| 43 | +to members via runtime reflection (where applicable), nor does it |
| 44 | +necessarily restrict visibility of symbols in a linked binary. |
| 45 | + |
| 46 | +### Globals and Members |
| 47 | + |
| 48 | +All globals and members have a default access level of `internal`, |
| 49 | +except within extensions (as described below). |
| 50 | + |
| 51 | +A declaration may have any access level less than or equal to the access |
| 52 | +level of its type. That is, a `private` constant can have `public` type, |
| 53 | +but not the other way around. It is legal for a member to have greater |
| 54 | +access than its enclosing type, but this has no effect. |
| 55 | + |
| 56 | +Accessors for variables have the same access level as their associated |
| 57 | +variable. The setter may be explicitly annotated with an access level |
| 58 | +less than or equal to the access level of the variable; this is written |
| 59 | +as `private(set)` or `internal(set)` before the `var` introducer. |
| 60 | + |
| 61 | +An initializer, method, subscript, or property may have any access level |
| 62 | +less than or equal to the access level of its type (including the |
| 63 | +implicit \'Self\' type), with a few additional rules: |
| 64 | + |
| 65 | +- If a member is used to satisfy a protocol requirement, its access |
| 66 | + level must be at least as high as the protocol conformance\'s; see |
| 67 | + ["Protocols"](#protocols) below. |
| 68 | +- If an initializer is `required` by a superclass, its access level |
| 69 | + must be at least as high as the access level of the subclass itself. |
| 70 | +- Accessors for subscripts follow the same rules as accessors for |
| 71 | + variables. |
| 72 | +- A member may be overridden whenever it is accessible. |
| 73 | + |
| 74 | +The implicit memberwise initializer for a struct has the minimum access |
| 75 | +level of all of the struct\'s stored properties, except that if all |
| 76 | +properties are `public` the initializer is `internal`. The implicit |
| 77 | +no-argument initializer for structs and classes follows the default |
| 78 | +access level for the type. |
| 79 | + |
| 80 | +Currently, enum cases always have the same access level as the enclosing |
| 81 | +enum. |
| 82 | + |
| 83 | +Deinitializers are only invoked by the runtime and do not nominally have |
| 84 | +access. Internally, the compiler represents them as having the same |
| 85 | +access level as the enclosing type. |
| 86 | + |
| 87 | +### Protocols |
| 88 | + |
| 89 | +A protocol may have any access level less than or equal to the access |
| 90 | +levels of the protocols it refines. That is, a `private` ExtendedWidget |
| 91 | +protocol can refine a `public` Widget protocol, but not the other way |
| 92 | +around. |
| 93 | + |
| 94 | +The access level of a requirement is the access level of the enclosing |
| 95 | +protocol, even when the protocol is `public`. Currently, requirements |
| 96 | +may not be given a lower access level than the enclosing protocol. |
| 97 | + |
| 98 | +Swift does not currently support private protocol conformances, so for |
| 99 | +runtime consistency, the access level of the conformance of type T to |
| 100 | +protocol P is equal to the minimum of T\'s access level and P\'s access |
| 101 | +level; that is, the conformance is accessible whenever both T and P are |
| 102 | +accessible. This does not change if the protocol is conformed to in an |
| 103 | +extension. (The access level of a conformance is not currently reflected |
| 104 | +in the source, but is a useful concept for applying restrictions |
| 105 | +consistently.) |
| 106 | + |
| 107 | +All members used to satisfy a conformance must have an access level at |
| 108 | +least as high as the conformance\'s. This ensures consistency between |
| 109 | +views of the type; if any member has a *lower* access level than the |
| 110 | +conformance, then the member could be accessed anyway through a generic |
| 111 | +function constrained by the protocol. |
| 112 | + |
| 113 | +_**Note**_ |
| 114 | + |
| 115 | +This rule disallows an `internal` member of a protocol extension to |
| 116 | +satisfy a `public` requirement for a `public` type. Removing this |
| 117 | +limitation is not inherently unsafe, but (a) may be unexpected given the |
| 118 | +lack of explicit reference to the member, and (b) results in references |
| 119 | +to non-public symbols in the current representation. |
| 120 | + |
| 121 | +A protocol may be used as a type whenever it is accessible. A nominal |
| 122 | +can conform to a protocol whenever the protocol is accessible. |
| 123 | + |
| 124 | +### Structs, Enums, and Classes |
| 125 | + |
| 126 | +A struct, enum, or class may be used as a type whenever it is |
| 127 | +accessible. A struct, enum, or class may be extended whenever it is |
| 128 | +accessible. |
| 129 | + |
| 130 | +A class may be subclassed whenever it is accessible. A class may have |
| 131 | +any access level less than or equal to the access level of its |
| 132 | +superclass. |
| 133 | + |
| 134 | +Members within constrained extensions must have access less than or |
| 135 | +equal to the access level of the types used in the constraints. |
| 136 | + |
| 137 | +An extension may be marked with an explicit access modifier (e.g. |
| 138 | +`private extension`), in which case the default access level of members |
| 139 | +within the extension is changed to match. No member within such an |
| 140 | +extension may have broader access than the new default. |
| 141 | + |
| 142 | +Extensions with explicit access modifiers may not add new protocol |
| 143 | +conformances, since Swift does not support private protocol conformances |
| 144 | +(see ["Protocols"](#protocols) above). |
| 145 | + |
| 146 | +A type may conform to a protocol with lower access than the type itself. |
| 147 | + |
| 148 | +### Types |
| 149 | + |
| 150 | +A nominal type\'s access level is the same as the access level of the |
| 151 | +nominal declaration itself. A generic type\'s access level is the |
| 152 | +minimum of the access level of the base type and the access levels of |
| 153 | +all generic argument types. |
| 154 | + |
| 155 | +A tuple type\'s access level is the minimum of the access levels of its |
| 156 | +elements. A function type\'s access level is the minimum of the access |
| 157 | +levels of its input and return types. |
| 158 | + |
| 159 | +A typealias may have any access level up to the access level of the type |
| 160 | +it aliases. That is, a `private` typealias can refer to a `public` type, |
| 161 | +but not the other way around. This includes associated types used to |
| 162 | +satisfy protocol conformances. |
| 163 | + |
| 164 | +## Runtime Guarantees |
| 165 | + |
| 166 | +Non-`public` members of a class or extension will not be seen by |
| 167 | +subclasses or other extensions from outside the module. Therefore, |
| 168 | +members of a subclass or extension will not conflict with or |
| 169 | +inadvertently be considered to override non-accessible members of the |
| 170 | +superclass. |
| 171 | + |
| 172 | +Access levels lower than `public` increase opportunities for |
| 173 | +devirtualization, though it is still possible to put a subclass of a |
| 174 | +`private` class within the same scope. |
| 175 | + |
| 176 | +Most information about a non-`public` entity still has to be put into a |
| 177 | +module file for now, since we don\'t have resilience implemented. This |
| 178 | +can be improved later, and is no more revealing than the information |
| 179 | +currently available in the runtime for pure Objective-C classes. |
| 180 | + |
| 181 | +### Interaction with Objective-C |
| 182 | + |
| 183 | +If an entity is exposed to Objective-C, most of the runtime guarantees |
| 184 | +and optimization opportunities go out the window. We have to use a |
| 185 | +particular selector for members, everything can be inspected at runtime, |
| 186 | +and even a private member can cause selector conflicts. In this case, |
| 187 | +access control is only useful for discipline purposes. |
| 188 | + |
| 189 | +Members explicitly marked `private` or `fileprivate` are *not* exposed |
| 190 | +to Objective-C unless they are also marked `@objc` (or `@IBAction` or |
| 191 | +similar), even if declared within a class implicitly or explicitly |
| 192 | +marked `@objc`. |
| 193 | + |
| 194 | +Any `public` entities will be included in the generated header. In an |
| 195 | +application or unit test target, `internal` entities will be exposed as |
| 196 | +well. |
| 197 | + |
| 198 | +## Non-Goals: \"class-only\" and \"protected\" |
| 199 | + |
| 200 | +This proposal omits two forms of access control commonly found in other |
| 201 | +languages, a \"class-implementation-only\" access (often called |
| 202 | +\"private\"), and a \"class and any subclasses\" access (often called |
| 203 | +\"protected\"). We chose not to include these levels of access control |
| 204 | +because they do not add useful functionality beyond `private`, |
| 205 | +`fileprivate`, `internal`, and `public`. |
| 206 | + |
| 207 | +### "class-only" |
| 208 | + |
| 209 | +If \"class-only\" includes extensions of the class, it is clear that |
| 210 | +it provides no protection at all, since a class may be extended from |
| 211 | +any context where it is accessible. So a hypothetical \"class-only\" |
| 212 | +must already be limited with regards to extensions. Beyond that, |
| 213 | +however, a \"class-only\" limit forces code to be declared within |
| 214 | +the class that might otherwise naturally be a top-level helper or an |
| 215 | +extension method on another type. |
| 216 | + |
| 217 | +`private` and `fileprivate` serve the use case of limiting access to |
| 218 | +the implementation details of a class (even from the rest of the |
| 219 | +module!) while not tying access to the notion of type. |
| 220 | + |
| 221 | +### "protected" |
| 222 | + |
| 223 | +"protected\" access provides no guarantees of information hiding, |
| 224 | +since any subclass can now access the implementation details of its |
| 225 | +superclass\-\--and expose them publicly, if it so chooses. This |
| 226 | +interacts poorly with our future plans for resilient APIs. |
| 227 | +Additionally, it increases the complexity of the access control |
| 228 | +model for both the compiler and for developers, and like |
| 229 | +\"class-only\" it is not immediately clear how it interacts with |
| 230 | +extensions. |
| 231 | + |
| 232 | +Though it is not compiler-enforced, members that might be considered |
| 233 | +\"protected\" are effectively publicly accessible, and thus should |
| 234 | +be marked `public` in Swift. They can still be documented as |
| 235 | +intended for overriding rather than for subclassing, but the |
| 236 | +specific details of this are best dealt with on a case-by-case |
| 237 | +basis. |
| 238 | + |
| 239 | +## Potential Future Directions |
| 240 | + |
| 241 | +- Allowing `private` or `internal` protocol conformances, which are |
| 242 | + only accessible at compile-time from a particular access scope. |
| 243 | +- Limiting particular capabilities, such as marking something |
| 244 | + `final(public)` to restrict subclassing or overriding outside of the |
| 245 | + current module. |
| 246 | +- Allowing the Swift parts of a mixed-source framework to access |
| 247 | + private headers. |
| 248 | +- Revealing `internal` Swift API in a mixed-source framework in a |
| 249 | + second generated header. |
| 250 | +- Levels of `public`, for example `public("SPI")`. |
| 251 | +- Enum cases less accessible than the enum. |
| 252 | +- Protocol requirements less accessible than the protocol. |
0 commit comments