Skip to content

Commit 0f1d5e8

Browse files
authored
docs: convert AccessControl.rst to Markdown (swiftlang#37217)
Converts one of the doc files from reStructuredText to Markdown. Continues work on SR-7454.
1 parent f9859a5 commit 0f1d5e8

File tree

4 files changed

+253
-264
lines changed

4 files changed

+253
-264
lines changed

docs/AccessControl.md

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
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

Comments
 (0)