Files
gh-kylehughes-the-unofficia…/skills/programming-swift/LanguageGuide/AccessControl.md
2025-11-30 08:36:15 +08:00

1488 lines
55 KiB
Markdown

# Access Control
Manage the visibility of code by declaration, file, and module.
*Access control* restricts access to parts of your code
from code in other source files and modules.
This feature enables you to hide the implementation details of your code,
and to specify a preferred interface through which that code can be accessed and used.
You can assign specific access levels to individual types
(classes, structures, and enumerations),
as well as to properties, methods, initializers, and subscripts belonging to those types.
Protocols can be restricted to a certain context,
as can global constants, variables, and functions.
In addition to offering various levels of access control,
Swift reduces the need to specify explicit access control levels
by providing default access levels for typical scenarios.
Indeed, if you are writing a single-target app,
you may not need to specify explicit access control levels at all.
> Note: The various aspects of your code that can have access control applied to them
> (properties, types, functions, and so on)
> are referred to as “entities” in the sections below, for brevity.
## Modules, Source Files, and Packages
Swift's access control model is based on the concept of
modules, source files, and packages.
A *module* is a single unit of code distribution ---
a framework or application that's built and shipped as a single unit
and that can be imported by another module with Swift's `import` keyword.
Each build target (such as an app bundle or framework) in Xcode
is treated as a separate module in Swift.
If you group together aspects of your app's code as a stand-alone framework ---
perhaps to encapsulate and reuse that code across multiple applications ---
then everything you define within that framework will be part of a separate module
when it's imported and used within an app,
or when it's used within another framework.
A *source file* is a single Swift source code file within a module
(in effect, a single file within an app or framework).
Although it's common to define individual types in separate source files,
a single source file can contain definitions for multiple types, functions, and so on.
A *package* is a group of modules that you develop as a unit.
You define the modules that form a package
as part of configuring the build system you're using,
not as part of your Swift source code.
For example, if you use Swift Package Manager to build your code,
you define a package in your `Package.swift` file
using APIs from the [PackageDescription][] module,
and if you use Xcode, you specify the package name
in the Package Access Identifier build setting.
[PackageDescription]: https://developer.apple.com/documentation/packagedescription
## Access Levels
Swift provides six different *access levels* for entities within your code.
These access levels are relative to the source file in which an entity is defined,
the module that source file belongs to,
and the package that the module belongs to.
- *Open access* and *public access*
enable entities to be used within any source file from their defining module,
and also in a source file from another module that imports the defining module.
You typically use open or public access when specifying the public interface to a framework.
The difference between open and public access is described below.
- *Package access*
enables entities to be used within
any source files from their defining package
but not in any source file outside of that package.
You typically use package access
within an app or framework that's structured into multiple modules.
- *Internal access*
enables entities to be used within any source file from their defining module,
but not in any source file outside of that module.
You typically use internal access when defining
an app's or a framework's internal structure.
- *File-private access*
restricts the use of an entity to its own defining source file.
Use file-private access to hide the implementation details of
a specific piece of functionality
when those details are used within an entire file.
- *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.
Open access is the highest (least restrictive) access level
and private access is the lowest (most restrictive) access level.
Open access applies only to classes and class members,
and it differs from public access
by allowing code outside the module to subclass and override,
as discussed below in <doc:AccessControl#Subclassing>.
Marking a class as open explicitly indicates
that you've considered the impact of code from other modules
using that class as a superclass,
and that you've designed your class's code accordingly.
### Guiding Principle of Access Levels
Access levels in Swift follow an overall guiding principle:
*No entity can be defined in terms of another entity that has
a lower (more restrictive) access level.*
For example:
- A public variable can't be defined as having an internal, file-private, or private type,
because the type might not be available everywhere that the public variable is used.
- A function can't have a higher access level than its parameter types and return type,
because the function could be used in situations where
its constituent types are unavailable to the surrounding code.
The specific implications of this guiding principle for different aspects of the language
are covered in detail below.
### Default Access Levels
All entities in your code
(with a few specific exceptions, as described later in this chapter)
have a default access level of internal
if you don't specify an explicit access level yourself.
As a result, in many cases you don't need to specify
an explicit access level in your code.
### Access Levels for Single-Target Apps
When you write a simple single-target app,
the code in your app is typically self-contained within the app
and doesn't need to be made available outside of the app's module.
The default access level of internal already matches this requirement.
Therefore, you don't need to specify a custom access level.
You may, however, want to mark some parts of your code as file private or private
in order to hide their implementation details from other code within the app's module.
### Access Levels for Frameworks
When you develop a framework,
mark the public-facing interface to that framework
as open or public so that it can be viewed and accessed by other modules,
such as an app that imports the framework.
This public-facing interface is the application programming interface
(or API) for the framework.
> Note: Any internal implementation details of your framework can still use
> the default access level of internal,
> or can be marked as private or file private if you want to hide them from
> other parts of the framework's internal code.
> You need to mark an entity as open or public only if you want it to become
> part of your framework's API.
### Access Levels for Unit Test Targets
When you write an app with a unit test target,
the code in your app needs to be made available to that module in order to be tested.
By default, only entities marked as open or public
are accessible to other modules.
However, a unit test target can access any internal entity,
if you mark the import declaration for a product module with the `@testable` attribute
and compile that product module with testing enabled.
## Access Control Syntax
Define the access level for an entity by placing
one of the modifiers listed in <doc:AccessControl#Access-Levels>,
such as `public` or `private`,
at the beginning of the entity's declaration.
For example:
```swift
public class SomePublicClass {}
internal struct SomeInternalStruct() {}
private func somePrivateFunction() {}
```
The code above declares `SomePublicClass` as public,
`SomeInternalStruct` as internal,
and `somePrivateFunction()` as private.
If you don't write an explicit access level,
the default access level modifier is `internal`,
as described in <doc:AccessControl#Default-Access-Levels>.
For example, in the code below, `SomeInternalStruct` is implicitly internal:
```swift
struct SomeInternalStruct() {}
```
## Custom Types
If you want to specify an explicit access level for a custom type,
do so at the point that you define the type.
The new type can then be used wherever its access level permits.
For example, if you define a file-private class,
that class can only be used as the type of a property,
or as a function parameter or return type,
in the source file in which the file-private class is defined.
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.
If you define a type's access level as internal or public
(or use the default access level of internal
without specifying an access level explicitly),
the default access level of the type's members will be internal.
> Important: A public type defaults to having internal members, not public members.
> If you want a type member to be public, you must explicitly mark it as such.
> This requirement ensures that the public-facing API for a type is
> something you opt in to publishing,
> and avoids presenting the internal workings of a type as public API by mistake.
```swift
public class SomePublicClass { // explicitly public class
public var somePublicProperty = 0 // explicitly public class member
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
class SomeInternalClass { // implicitly internal class
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
fileprivate class SomeFilePrivateClass { // explicitly file-private class
func someFilePrivateMethod() {} // implicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
private class SomePrivateClass { // explicitly private class
func somePrivateMethod() {} // implicitly private class member
}
```
<!--
- test: `accessControl, accessControlWrong`
```swifttest
-> public class SomePublicClass { // explicitly public class
public var somePublicProperty = 0 // explicitly public class member
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
-> class SomeInternalClass { // implicitly internal class
var someInternalProperty = 0 // implicitly internal class member
fileprivate func someFilePrivateMethod() {} // explicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
-> fileprivate class SomeFilePrivateClass { // explicitly file-private class
func someFilePrivateMethod() {} // implicitly file-private class member
private func somePrivateMethod() {} // explicitly private class member
}
-> private class SomePrivateClass { // explicitly private class
func somePrivateMethod() {} // implicitly private class member
}
```
-->
### Tuple Types
The access level for a tuple type is
the most restrictive access level of all types used in that tuple.
For example, if you compose a tuple from two different types,
one with internal access and one with private access,
the access level for that compound tuple type will be private.
<!--
- test: `tupleTypes_Module1, tupleTypes_Module1_PublicAndInternal, tupleTypes_Module1_Private`
```swifttest
-> public struct PublicStruct {}
-> internal struct InternalStruct {}
-> fileprivate struct FilePrivateStruct {}
-> public func returnPublicTuple() -> (PublicStruct, PublicStruct) {
return (PublicStruct(), PublicStruct())
}
-> func returnInternalTuple() -> (PublicStruct, InternalStruct) {
return (PublicStruct(), InternalStruct())
}
-> fileprivate func returnFilePrivateTuple() -> (PublicStruct, FilePrivateStruct) {
return (PublicStruct(), FilePrivateStruct())
}
```
-->
<!--
- test: `tupleTypes_Module1_PublicAndInternal`
```swifttest
// tuples with (at least) internal members can be accessed within their own module
-> let publicTuple = returnPublicTuple()
-> let internalTuple = returnInternalTuple()
```
-->
<!--
- test: `tupleTypes_Module1_Private`
```swifttest
// a tuple with one or more private members can't be accessed from outside of its source file
-> let privateTuple = returnFilePrivateTuple()
!$ error: cannot find 'returnFilePrivateTuple' in scope
!! let privateTuple = returnFilePrivateTuple()
!! ^~~~~~~~~~~~~~~~~~~~~~
```
-->
<!--
- test: `tupleTypes_Module2_Public`
```swifttest
// a public tuple with all-public members can be used in another module
-> import tupleTypes_Module1
-> let publicTuple = returnPublicTuple()
```
-->
<!--
- test: `tupleTypes_Module2_InternalAndPrivate`
```swifttest
// tuples with internal or private members can't be used outside of their own module
-> import tupleTypes_Module1
-> let internalTuple = returnInternalTuple()
-> let privateTuple = returnFilePrivateTuple()
!$ error: cannot find 'returnInternalTuple' in scope
!! let internalTuple = returnInternalTuple()
!! ^~~~~~~~~~~~~~~~~~~
!$ error: cannot find 'returnFilePrivateTuple' in scope
!! let privateTuple = returnFilePrivateTuple()
!! ^~~~~~~~~~~~~~~~~~~~~~
```
-->
> Note: Tuple types don't have a standalone definition in the way that
> classes, structures, enumerations, and functions do.
> A tuple type's access level is determined automatically
> from the types that make up the tuple type,
> and can't be specified explicitly.
### Function Types
The access level for a function type is calculated as
the most restrictive access level of the function's parameter types and return type.
You must specify the access level explicitly as part of the function's definition
if the function's calculated access level doesn't match the contextual default.
The example below defines a global function called `someFunction()`,
without providing a specific access-level modifier for the function itself.
You might expect this function to have the default access level of “internal”,
but this isn't the case.
In fact, `someFunction()` won't compile as written below:
```swift
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}
```
<!--
- test: `accessControlWrong`
```swifttest
-> func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
>> return (SomeInternalClass(), SomePrivateClass())
}
!! /tmp/swifttest.swift:19:6: error: function must be declared private or fileprivate because its result uses a private type
!! func someFunction() -> (SomeInternalClass, SomePrivateClass) {
!! ^
```
-->
The function's return type is
a tuple type composed from two of the custom classes defined above in <doc:AccessControl#Custom-Types>.
One of these classes is defined as internal,
and the other is defined as private.
Therefore, the overall access level of the compound tuple type is private
(the minimum access level of the tuple's constituent types).
Because the function's return type is private,
you must mark the function's overall access level with the `private` modifier
for the function declaration to be valid:
```swift
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}
```
<!--
- test: `accessControl`
```swifttest
-> private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
>> return (SomeInternalClass(), SomePrivateClass())
}
```
-->
It's not valid to mark the definition of `someFunction()`
with the `public` or `internal` modifiers,
or to use the default setting of internal,
because public or internal users of the function might not have appropriate access
to the private class used in the function's return type.
### Enumeration Types
The individual cases of an enumeration automatically receive the same access level as
the enumeration they belong to.
You can't specify a different access level for individual enumeration cases.
In the example below,
the `CompassPoint` enumeration has an explicit access level of public.
The enumeration cases `north`, `south`, `east`, and `west`
therefore also have an access level of public:
```swift
public enum CompassPoint {
case north
case south
case east
case west
}
```
<!--
- test: `enumerationCases`
```swifttest
-> public enum CompassPoint {
case north
case south
case east
case west
}
```
-->
<!--
- test: `enumerationCases_Module1`
```swifttest
-> public enum CompassPoint {
case north
case south
case east
case west
}
```
-->
<!--
- test: `enumerationCases_Module2`
```swifttest
-> import enumerationCases_Module1
-> let north = CompassPoint.north
```
-->
#### Raw Values and Associated Values
The types used for any raw values or associated values in an enumeration definition
must have an access level at least as high as the enumeration's access level.
For example,
you can't use a private type as the raw-value type of
an enumeration with an internal access level.
### Nested Types
The access level of a nested type is the same as its containing type,
unless the containing type is public.
Nested types defined within a public type
have an automatic access level of internal.
If you want a nested type within a public type to be publicly available,
you must explicitly declare the nested type as public.
<!--
- test: `nestedTypes_Module1, nestedTypes_Module1_PublicAndInternal, nestedTypes_Module1_Private`
```swifttest
-> public struct PublicStruct {
public enum PublicEnumInsidePublicStruct { case a, b }
internal enum InternalEnumInsidePublicStruct { case a, b }
private enum PrivateEnumInsidePublicStruct { case a, b }
enum AutomaticEnumInsidePublicStruct { case a, b }
}
-> internal struct InternalStruct {
internal enum InternalEnumInsideInternalStruct { case a, b }
private enum PrivateEnumInsideInternalStruct { case a, b }
enum AutomaticEnumInsideInternalStruct { case a, b }
}
-> private struct FilePrivateStruct {
enum AutomaticEnumInsideFilePrivateStruct { case a, b }
private enum PrivateEnumInsideFilePrivateStruct { case a, b }
}
-> private struct PrivateStruct {
enum AutomaticEnumInsidePrivateStruct { case a, b }
private enum PrivateEnumInsidePrivateStruct { case a, b }
}
```
-->
<!--
- test: `nestedTypes_Module1_PublicAndInternal`
```swifttest
// these are all expected to succeed within the same module
-> let publicNestedInsidePublic = PublicStruct.PublicEnumInsidePublicStruct.a
-> let internalNestedInsidePublic = PublicStruct.InternalEnumInsidePublicStruct.a
-> let automaticNestedInsidePublic = PublicStruct.AutomaticEnumInsidePublicStruct.a
-> let internalNestedInsideInternal = InternalStruct.InternalEnumInsideInternalStruct.a
-> let automaticNestedInsideInternal = InternalStruct.AutomaticEnumInsideInternalStruct.a
```
-->
<!--
- test: `nestedTypes_Module1_Private`
```swifttest
// these are all expected to fail, because they're private to the other file
-> let privateNestedInsidePublic = PublicStruct.PrivateEnumInsidePublicStruct.a
-> let privateNestedInsideInternal = InternalStruct.PrivateEnumInsideInternalStruct.a
-> let privateNestedInsidePrivate = PrivateStruct.PrivateEnumInsidePrivateStruct.a
-> let automaticNestedInsidePrivate = PrivateStruct.AutomaticEnumInsidePrivateStruct.a
!$ error: 'PrivateEnumInsidePublicStruct' is inaccessible due to 'private' protection level
!! let privateNestedInsidePublic = PublicStruct.PrivateEnumInsidePublicStruct.a
!! ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!$ note: 'PrivateEnumInsidePublicStruct' declared here
!! private enum PrivateEnumInsidePublicStruct { case a, b }
!! ^
!$ error: 'PrivateEnumInsideInternalStruct' is inaccessible due to 'private' protection level
!! let privateNestedInsideInternal = InternalStruct.PrivateEnumInsideInternalStruct.a
!! ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!$ note: 'PrivateEnumInsideInternalStruct' declared here
!! private enum PrivateEnumInsideInternalStruct { case a, b }
!! ^
!$ error: cannot find 'PrivateStruct' in scope
!! let privateNestedInsidePrivate = PrivateStruct.PrivateEnumInsidePrivateStruct.a
!! ^~~~~~~~~~~~~
!$ error: cannot find 'PrivateStruct' in scope
!! let automaticNestedInsidePrivate = PrivateStruct.AutomaticEnumInsidePrivateStruct.a
!! ^~~~~~~~~~~~~
```
-->
<!--
- test: `nestedTypes_Module2_Public`
```swifttest
// this is the only expected to succeed within the second module
-> import nestedTypes_Module1
-> let publicNestedInsidePublic = PublicStruct.PublicEnumInsidePublicStruct.a
```
-->
<!--
- test: `nestedTypes_Module2_InternalAndPrivate`
```swifttest
// these are all expected to fail, because they're private or internal to the other module
-> import nestedTypes_Module1
-> let internalNestedInsidePublic = PublicStruct.InternalEnumInsidePublicStruct.a
-> let automaticNestedInsidePublic = PublicStruct.AutomaticEnumInsidePublicStruct.a
-> let privateNestedInsidePublic = PublicStruct.PrivateEnumInsidePublicStruct.a
-> let internalNestedInsideInternal = InternalStruct.InternalEnumInsideInternalStruct.a
-> let automaticNestedInsideInternal = InternalStruct.AutomaticEnumInsideInternalStruct.a
-> let privateNestedInsideInternal = InternalStruct.PrivateEnumInsideInternalStruct.a
-> let privateNestedInsidePrivate = PrivateStruct.PrivateEnumInsidePrivateStruct.a
-> let automaticNestedInsidePrivate = PrivateStruct.AutomaticEnumInsidePrivateStruct.a
!$ error: 'InternalEnumInsidePublicStruct' is inaccessible due to 'internal' protection level
!! let internalNestedInsidePublic = PublicStruct.InternalEnumInsidePublicStruct.a
!! ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!$ note: 'InternalEnumInsidePublicStruct' declared here
!! internal enum InternalEnumInsidePublicStruct {
!! ^
!$ error: 'AutomaticEnumInsidePublicStruct' is inaccessible due to 'internal' protection level
!! let automaticNestedInsidePublic = PublicStruct.AutomaticEnumInsidePublicStruct.a
!! ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!$ note: 'AutomaticEnumInsidePublicStruct' declared here
!! internal enum AutomaticEnumInsidePublicStruct {
!! ^
!$ error: 'PrivateEnumInsidePublicStruct' is inaccessible due to 'private' protection level
!! let privateNestedInsidePublic = PublicStruct.PrivateEnumInsidePublicStruct.a
!! ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!$ note: 'PrivateEnumInsidePublicStruct' declared here
!! private enum PrivateEnumInsidePublicStruct {
!! ^
!$ error: cannot find 'InternalStruct' in scope
!! let internalNestedInsideInternal = InternalStruct.InternalEnumInsideInternalStruct.a
!! ^~~~~~~~~~~~~~
!$ error: cannot find 'InternalStruct' in scope
!! let automaticNestedInsideInternal = InternalStruct.AutomaticEnumInsideInternalStruct.a
!! ^~~~~~~~~~~~~~
!$ error: cannot find 'InternalStruct' in scope
!! let privateNestedInsideInternal = InternalStruct.PrivateEnumInsideInternalStruct.a
!! ^~~~~~~~~~~~~~
!$ error: cannot find 'PrivateStruct' in scope
!! let privateNestedInsidePrivate = PrivateStruct.PrivateEnumInsidePrivateStruct.a
!! ^~~~~~~~~~~~~
!$ error: cannot find 'PrivateStruct' in scope
!! let automaticNestedInsidePrivate = PrivateStruct.AutomaticEnumInsidePrivateStruct.a
!! ^~~~~~~~~~~~~
```
-->
## Subclassing
You can subclass any class
that can be accessed in the current access context
and that's defined in the same module as the subclass.
You can also subclass any open class
that's defined in a different module.
A subclass can't have a higher access level than its superclass ---
for example, you can't write a public subclass of an internal superclass.
In addition,
for classes that are defined in the same module,
you can override any class member
(method, property, initializer, or subscript)
that's visible in a certain access context.
For classes that are defined in another module,
you can override any open class member.
An override can make an inherited class member more accessible than its superclass version.
In the example below, class `A` is a public class with a file-private method called `someMethod()`.
Class `B` is a subclass of `A`, with a reduced access level of “internal”.
Nonetheless, class `B` provides an override of `someMethod()`
with an access level of “internal”, which is *higher* than
the original implementation of `someMethod()`:
```swift
public class A {
fileprivate func someMethod() {}
}
internal class B: A {
override internal func someMethod() {}
}
```
<!--
- test: `subclassingNoCall`
```swifttest
-> public class A {
fileprivate func someMethod() {}
}
-> internal class B: A {
override internal func someMethod() {}
}
```
-->
It's even valid for a subclass member to call
a superclass member that has lower access permissions than the subclass member,
as long as the call to the superclass's member takes place within
an allowed access level context
(that is, within the same source file as the superclass for a file-private member call,
or within the same module as the superclass for an internal member call):
```swift
public class A {
fileprivate func someMethod() {}
}
internal class B: A {
override internal func someMethod() {
super.someMethod()
}
}
```
<!--
- test: `subclassingWithCall`
```swifttest
-> public class A {
fileprivate func someMethod() {}
}
-> internal class B: A {
override internal func someMethod() {
super.someMethod()
}
}
```
-->
Because superclass `A` and subclass `B` are defined in the same source file,
it's valid for the `B` implementation of `someMethod()` to call
`super.someMethod()`.
## Constants, Variables, Properties, and Subscripts
A constant, variable, or property can't be more public than its type.
It's not valid to write a public property with a private type, for example.
Similarly, a subscript can't be more public than either its index type or return type.
If a constant, variable, property, or subscript makes use of a private type,
the constant, variable, property, or subscript must also be marked as `private`:
```swift
private var privateInstance = SomePrivateClass()
```
<!--
- test: `accessControl`
```swifttest
-> private var privateInstance = SomePrivateClass()
```
-->
<!--
- test: `useOfPrivateTypeRequiresPrivateModifier`
```swifttest
-> class Scope { // Need to be in a scope to meaningfully use private (vs fileprivate)
-> private class SomePrivateClass {}
-> let privateConstant = SomePrivateClass()
!! /tmp/swifttest.swift:3:5: error: property must be declared private because its type 'Scope.SomePrivateClass' uses a private type
!! let privateConstant = SomePrivateClass()
!! ^
-> var privateVariable = SomePrivateClass()
!! /tmp/swifttest.swift:4:5: error: property must be declared private because its type 'Scope.SomePrivateClass' uses a private type
!! var privateVariable = SomePrivateClass()
!! ^
-> class C {
var privateProperty = SomePrivateClass()
subscript(index: Int) -> SomePrivateClass {
return SomePrivateClass()
}
}
-> } // End surrounding scope
!! /tmp/swifttest.swift:6:8: error: property must be declared private because its type 'Scope.SomePrivateClass' uses a private type
!! var privateProperty = SomePrivateClass()
!! ^
!! /tmp/swifttest.swift:7:4: error: subscript must be declared private because its element type uses a private type
!! subscript(index: Int) -> SomePrivateClass {
!! ^ ~~~~~~~~~~~~~~~~
!! /tmp/swifttest.swift:2:15: note: type declared here
!! private class SomePrivateClass {}
!! ^
```
-->
### Getters and Setters
Getters and setters for constants, variables, properties, and subscripts
automatically receive the same access level as
the constant, variable, property, or subscript they belong to.
You can give a setter a *lower* access level than its corresponding getter,
to restrict the read-write scope of that variable, property, or subscript.
You assign a lower access level by writing
`fileprivate(set)`, `private(set)`, `internal(set)`, or `package(set)`
before the `var` or `subscript` introducer.
> Note: This rule applies to stored properties as well as computed properties.
> Even though you don't write an explicit getter and setter for a stored property,
> Swift still synthesizes an implicit getter and setter for you
> to provide access to the stored property's backing storage.
> Use `fileprivate(set)`, `private(set)`, `internal(set)`, and `package(set)`
> to change the access level
> of this synthesized setter in exactly the same way as for an explicit setter
> in a computed property.
The example below defines a structure called `TrackedString`,
which keeps track of the number of times a string property is modified:
```swift
struct TrackedString {
private(set) var numberOfEdits = 0
var value: String = "" {
didSet {
numberOfEdits += 1
}
}
}
```
<!--
- test: `reducedSetterScope, reducedSetterScope_error`
```swifttest
-> struct TrackedString {
private(set) var numberOfEdits = 0
var value: String = "" {
didSet {
numberOfEdits += 1
}
}
}
```
-->
The `TrackedString` structure defines a stored string property called `value`,
with an initial value of `""` (an empty string).
The structure also defines a stored integer property called `numberOfEdits`,
which is used to track the number of times that `value` is modified.
This modification tracking is implemented with
a `didSet` property observer on the `value` property,
which increments `numberOfEdits` every time the `value` property is set to a new value.
The `TrackedString` structure and the `value` property
don't provide an explicit access-level modifier,
and so they both receive the default access level of internal.
However, the access level for the `numberOfEdits` property
is marked with a `private(set)` modifier
to indicate that
the property's getter still has the default access level of internal,
but the property is settable only from within
code that's part of the `TrackedString` structure.
This enables `TrackedString` to modify the `numberOfEdits` property internally,
but to present the property as a read-only property
when it's used outside the structure's definition.
<!--
- test: `reducedSetterScope_error`
```swifttest
-> extension TrackedString {
mutating func f() { numberOfEdits += 1 }
}
// check that we can't set its value with from the same file
-> var s = TrackedString()
-> let resultA: Void = { s.numberOfEdits += 1 }()
!! /tmp/swifttest.swift:13:39: error: left side of mutating operator isn't mutable: 'numberOfEdits' setter is inaccessible
!! let resultA: Void = { s.numberOfEdits += 1 }()
!! ~~~~~~~~~~~~~~~ ^
```
-->
<!--
The assertion above must be compiled because of a REPL bug
<rdar://problem/54089342> REPL fails to enforce private(set) on struct property
-->
If you create a `TrackedString` instance and modify its string value a few times,
you can see the `numberOfEdits` property value update to match the number of modifications:
```swift
var stringToEdit = TrackedString()
stringToEdit.value = "This string will be tracked."
stringToEdit.value += " This edit will increment numberOfEdits."
stringToEdit.value += " So will this one."
print("The number of edits is \(stringToEdit.numberOfEdits)")
// Prints "The number of edits is 3".
```
<!--
- test: `reducedSetterScope`
```swifttest
-> var stringToEdit = TrackedString()
-> stringToEdit.value = "This string will be tracked."
-> stringToEdit.value += " This edit will increment numberOfEdits."
-> stringToEdit.value += " So will this one."
-> print("The number of edits is \(stringToEdit.numberOfEdits)")
<- The number of edits is 3
```
-->
Although you can query the current value of the `numberOfEdits` property
from within another source file,
you can't *modify* the property from another source file.
This restriction protects the implementation details of
the `TrackedString` edit-tracking functionality,
while still providing convenient access to an aspect of that functionality.
Note that you can assign an explicit access level for both
a getter and a setter if required.
The example below shows a version of the `TrackedString` structure
in which the structure is defined with an explicit access level of public.
The structure's members (including the `numberOfEdits` property)
therefore have an internal access level by default.
You can make the structure's `numberOfEdits` property getter public,
and its property setter private,
by combining the `public` and `private(set)` access-level modifiers:
```swift
public struct TrackedString {
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
```
<!--
- test: `reducedSetterScopePublic`
```swifttest
-> public struct TrackedString {
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
```
-->
<!--
- test: `reducedSetterScopePublic_Module1_Allowed, reducedSetterScopePublic_Module1_NotAllowed`
```swifttest
-> public struct TrackedString {
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
```
-->
<!--
- test: `reducedSetterScopePublic_Module1_Allowed`
```swifttest
// check that we can retrieve its value with the public getter from another file in the same module
-> var stringToEdit_Module1B = TrackedString()
-> let resultB = stringToEdit_Module1B.numberOfEdits
```
-->
<!--
- test: `reducedSetterScopePublic_Module1_NotAllowed`
```swifttest
// check that we can't set its value from another file in the same module
-> var stringToEdit_Module1C = TrackedString()
-> let resultC: Void = { stringToEdit_Module1C.numberOfEdits += 1 }()
!$ error: left side of mutating operator isn't mutable: 'numberOfEdits' setter is inaccessible
!! let resultC: Void = { stringToEdit_Module1C.numberOfEdits += 1 }()
!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
```
-->
<!--
- test: `reducedSetterScopePublic_Module2`
```swifttest
// check that we can retrieve its value with the public getter from a different module
-> import reducedSetterScopePublic_Module1_Allowed
-> var stringToEdit_Module2 = TrackedString()
-> let result2Read = stringToEdit_Module2.numberOfEdits
// check that we can't change its value from another module
-> let result2Write: Void = { stringToEdit_Module2.numberOfEdits += 1 }()
!$ error: left side of mutating operator isn't mutable: 'numberOfEdits' setter is inaccessible
!! let result2Write: Void = { stringToEdit_Module2.numberOfEdits += 1 }()
!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
```
-->
## Initializers
Custom initializers can be assigned an access level less than or equal to
the type that they initialize.
The only exception is for required initializers
(as defined in <doc:Initialization#Required-Initializers>).
A required initializer must have the same access level as the class it belongs to.
As with function and method parameters,
the types of an initializer's parameters can't be more private than
the initializer's own access level.
### Default Initializers
As described in <doc:Initialization#Default-Initializers>,
Swift automatically provides a *default initializer* without any arguments
for any structure or base class
that provides default values for all of its properties
and doesn't provide at least one initializer itself.
A default initializer has the same access level as the type it initializes,
unless that type is defined as `public`.
For a type that's defined as `public`,
the default initializer is considered internal.
If you want a public type to be initializable with a no-argument initializer
when used in another module,
you must explicitly provide a public no-argument initializer yourself
as part of the type's definition.
### Default Memberwise Initializers for Structure Types
The default memberwise initializer for a structure type is considered private
if any of the structure's stored properties are private.
Likewise, if any of the structure's stored properties are file private,
the initializer is file private.
Otherwise, the initializer has an access level of internal.
As with the default initializer above,
if you want a public structure type to be initializable with a memberwise initializer
when used in another module,
you must provide a public memberwise initializer yourself as part of the type's definition.
## Protocols
If you want to assign an explicit access level to a protocol type,
do so at the point that you define the protocol.
This enables you to create protocols that can only be adopted within
a certain access context.
The access level of each requirement within a protocol definition
is automatically set to the same access level as the protocol.
You can't set a protocol requirement to a different access level than
the protocol it supports.
This ensures that all of the protocol's requirements will be visible
on any type that adopts the protocol.
<!--
- test: `protocolRequirementsCannotBeDifferentThanTheProtocol`
```swifttest
-> public protocol PublicProtocol {
public var publicProperty: Int { get }
internal var internalProperty: Int { get }
fileprivate var filePrivateProperty: Int { get }
private var privateProperty: Int { get }
}
!$ error: 'public' modifier cannot be used in protocols
!! public var publicProperty: Int { get }
!! ^~~~~~~
!!-
!$ note: protocol requirements implicitly have the same access as the protocol itself
!! public var publicProperty: Int { get }
!! ^
!$ error: 'internal' modifier cannot be used in protocols
!! internal var internalProperty: Int { get }
!! ^~~~~~~~~
!!-
!$ note: protocol requirements implicitly have the same access as the protocol itself
!! internal var internalProperty: Int { get }
!! ^
!$ error: 'fileprivate' modifier cannot be used in protocols
!! fileprivate var filePrivateProperty: Int { get }
!! ^~~~~~~~~~~~
!!-
!$ note: protocol requirements implicitly have the same access as the protocol itself
!! fileprivate var filePrivateProperty: Int { get }
!! ^
!$ error: 'private' modifier cannot be used in protocols
!! private var privateProperty: Int { get }
!! ^~~~~~~~
!!-
!$ note: protocol requirements implicitly have the same access as the protocol itself
!! private var privateProperty: Int { get }
!! ^
```
-->
> Note: If you define a public protocol,
> the protocol's requirements require a public access level
> for those requirements when they're implemented.
> This behavior is different from other types,
> where a public type definition implies
> an access level of internal for the type's members.
<!--
- test: `protocols_Module1, protocols_Module1_PublicAndInternal, protocols_Module1_Private`
```swifttest
-> public protocol PublicProtocol {
var publicProperty: Int { get }
func publicMethod()
}
-> internal protocol InternalProtocol {
var internalProperty: Int { get }
func internalMethod()
}
-> fileprivate protocol FilePrivateProtocol {
var filePrivateProperty: Int { get }
func filePrivateMethod()
}
-> private protocol PrivateProtocol {
var privateProperty: Int { get }
func privateMethod()
}
```
-->
<!--
- test: `protocols_Module1_PublicAndInternal`
```swifttest
// these should all be allowed without problem
-> public class PublicClassConformingToPublicProtocol: PublicProtocol {
public var publicProperty = 0
public func publicMethod() {}
}
-> internal class InternalClassConformingToPublicProtocol: PublicProtocol {
var publicProperty = 0
func publicMethod() {}
}
-> private class PrivateClassConformingToPublicProtocol: PublicProtocol {
var publicProperty = 0
func publicMethod() {}
}
-> public class PublicClassConformingToInternalProtocol: InternalProtocol {
var internalProperty = 0
func internalMethod() {}
}
-> internal class InternalClassConformingToInternalProtocol: InternalProtocol {
var internalProperty = 0
func internalMethod() {}
}
-> private class PrivateClassConformingToInternalProtocol: InternalProtocol {
var internalProperty = 0
func internalMethod() {}
}
```
-->
<!--
- test: `protocols_Module1_Private`
```swifttest
// these will fail, because FilePrivateProtocol isn't visible outside of its file
-> public class PublicClassConformingToFilePrivateProtocol: FilePrivateProtocol {
var filePrivateProperty = 0
func filePrivateMethod() {}
}
!$ error: cannot find type 'FilePrivateProtocol' in scope
!! public class PublicClassConformingToFilePrivateProtocol: FilePrivateProtocol {
!! ^~~~~~~~~~~~~~~~~~~
// these will fail, because PrivateProtocol isn't visible outside of its file
-> public class PublicClassConformingToPrivateProtocol: PrivateProtocol {
var privateProperty = 0
func privateMethod() {}
}
!$ error: cannot find type 'PrivateProtocol' in scope
!! public class PublicClassConformingToPrivateProtocol: PrivateProtocol {
!! ^~~~~~~~~~~~~~~
```
-->
<!--
- test: `protocols_Module2_Public`
```swifttest
// these should all be allowed without problem
-> import protocols_Module1
-> public class PublicClassConformingToPublicProtocol: PublicProtocol {
public var publicProperty = 0
public func publicMethod() {}
}
-> internal class InternalClassConformingToPublicProtocol: PublicProtocol {
var publicProperty = 0
func publicMethod() {}
}
-> private class PrivateClassConformingToPublicProtocol: PublicProtocol {
var publicProperty = 0
func publicMethod() {}
}
```
-->
<!--
- test: `protocols_Module2_InternalAndPrivate`
```swifttest
// these will all fail, because InternalProtocol, FilePrivateProtocol, and PrivateProtocol
// aren't visible to other modules
-> import protocols_Module1
-> public class PublicClassConformingToInternalProtocol: InternalProtocol {
var internalProperty = 0
func internalMethod() {}
}
-> public class PublicClassConformingToFilePrivateProtocol: FilePrivateProtocol {
var filePrivateProperty = 0
func filePrivateMethod() {}
}
-> public class PublicClassConformingToPrivateProtocol: PrivateProtocol {
var privateProperty = 0
func privateMethod() {}
}
!$ error: cannot find type 'InternalProtocol' in scope
!! public class PublicClassConformingToInternalProtocol: InternalProtocol {
!! ^~~~~~~~~~~~~~~~
!$ error: cannot find type 'FilePrivateProtocol' in scope
!! public class PublicClassConformingToFilePrivateProtocol: FilePrivateProtocol {
!! ^~~~~~~~~~~~~~~~~~~
!$ error: cannot find type 'PrivateProtocol' in scope
!! public class PublicClassConformingToPrivateProtocol: PrivateProtocol {
!! ^~~~~~~~~~~~~~~
```
-->
### Protocol Inheritance
If you define a new protocol that inherits from an existing protocol,
the new protocol can have at most the same access level as the protocol it inherits from.
For example,
you can't write a public protocol that inherits from an internal protocol.
### Protocol Conformance
A type can conform to a protocol with a lower access level than the type itself.
For example, you can define a public type that can be used in other modules,
but whose conformance to an internal protocol can only be used
within the internal protocol's defining module.
The context in which a type conforms to a particular protocol
is the minimum of the type's access level and the protocol's access level.
For example, if a type is public, but a protocol it conforms to is internal,
the type's conformance to that protocol is also internal.
When you write or extend a type to conform to a protocol,
you must ensure that the type's implementation of each protocol requirement
has at least the same access level as the type's conformance to that protocol.
For example, if a public type conforms to an internal protocol,
the type's implementation of each protocol requirement must be at least internal.
> Note: In Swift, as in Objective-C, protocol conformance is global ---
> it isn't possible for a type to conform to a protocol in two different ways
> within the same program.
## Extensions
You can extend a class, structure, or enumeration in any access context
in which the class, structure, or enumeration is available.
Any type members added in an extension have the same default access level as
type members declared in the original type being extended.
If you extend a public or internal type, any new type members you add
have a default access level of internal.
If you extend a file-private type, any new type members you add
have a default access level of file private.
If you extend a private type, any new type members you add
have a default access level of private.
Alternatively, you can mark an extension with an explicit access-level modifier
(for example, `private`)
to set a new default access level for all members defined within the extension.
This new default can still be overridden within the extension
for individual type members.
You can't provide an explicit access-level modifier for an extension
if you're using that extension to add protocol conformance.
Instead, the protocol's own access level is used to provide
the default access level for each protocol requirement implementation within the extension.
<!--
- test: `extensions_Module1, extensions_Module1_PublicAndInternal, extensions_Module1_Private`
```swifttest
-> public struct PublicStruct {
public init() {}
func implicitlyInternalMethodFromStruct() -> Int { return 0 }
}
-> extension PublicStruct {
func implicitlyInternalMethodFromExtension() -> Int { return 0 }
}
-> fileprivate extension PublicStruct {
func filePrivateMethod() -> Int { return 0 }
}
-> var publicStructInSameFile = PublicStruct()
-> let sameFileA = publicStructInSameFile.implicitlyInternalMethodFromStruct()
-> let sameFileB = publicStructInSameFile.implicitlyInternalMethodFromExtension()
-> let sameFileC = publicStructInSameFile.filePrivateMethod()
```
-->
<!--
- test: `extensions_Module1_PublicAndInternal`
```swifttest
-> var publicStructInDifferentFile = PublicStruct()
-> let differentFileA = publicStructInDifferentFile.implicitlyInternalMethodFromStruct()
-> let differentFileB = publicStructInDifferentFile.implicitlyInternalMethodFromExtension()
```
-->
<!--
- test: `extensions_Module1_Private`
```swifttest
-> var publicStructInDifferentFile = PublicStruct()
-> let differentFileC = publicStructInDifferentFile.filePrivateMethod()
!$ error: 'filePrivateMethod' is inaccessible due to 'fileprivate' protection level
!! let differentFileC = publicStructInDifferentFile.filePrivateMethod()
!! ^~~~~~~~~~~~~~~~~
!$ note: 'filePrivateMethod()' declared here
!! func filePrivateMethod() -> Int { return 0 }
!! ^
```
-->
<!--
- test: `extensions_Module2`
```swifttest
-> import extensions_Module1
-> var publicStructInDifferentModule = PublicStruct()
-> let differentModuleA = publicStructInDifferentModule.implicitlyInternalMethodFromStruct()
!$ error: 'implicitlyInternalMethodFromStruct' is inaccessible due to 'internal' protection level
!! let differentModuleA = publicStructInDifferentModule.implicitlyInternalMethodFromStruct()
!! ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!$ note: 'implicitlyInternalMethodFromStruct()' declared here
!! internal func implicitlyInternalMethodFromStruct() -> Int
!! ^
-> let differentModuleB = publicStructInDifferentModule.implicitlyInternalMethodFromExtension()
!$ error: 'implicitlyInternalMethodFromExtension' is inaccessible due to 'internal' protection level
!! let differentModuleB = publicStructInDifferentModule.implicitlyInternalMethodFromExtension()
!! ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!$ note: 'implicitlyInternalMethodFromExtension()' declared here
!! internal func implicitlyInternalMethodFromExtension() -> Int
!! ^
-> let differentModuleC = publicStructInDifferentModule.filePrivateMethod()
!$ error: 'filePrivateMethod' is inaccessible due to 'fileprivate' protection level
!! let differentModuleC = publicStructInDifferentModule.filePrivateMethod()
!! ^~~~~~~~~~~~~~~~~
!$ note: 'filePrivateMethod()' declared here
!! fileprivate func filePrivateMethod() -> Int
!! ^
```
-->
### Private Members in Extensions
Extensions that are in the same file as
the class, structure, or enumeration that they extend
behave as if the code in the extension
had been written as part of the original type's declaration.
As a result, you can:
- Declare a private member in the original declaration,
and access that member from extensions in the same file.
- Declare a private member in one extension,
and access that member from another extension in the same file.
- Declare a private member in an extension,
and access that member from the original declaration in the same file.
This behavior means you can use extensions in the same way
to organize your code,
whether or not your types have private entities.
For example, given the following simple protocol:
```swift
protocol SomeProtocol {
func doSomething()
}
```
<!--
- test: `extensions_privatemembers`
```swifttest
-> protocol SomeProtocol {
func doSomething()
}
```
-->
You can use an extension to add protocol conformance, like this:
```swift
struct SomeStruct {
private var privateVariable = 12
}
extension SomeStruct: SomeProtocol {
func doSomething() {
print(privateVariable)
}
}
```
<!--
- test: `extensions_privatemembers`
```swifttest
-> struct SomeStruct {
private var privateVariable = 12
}
-> extension SomeStruct: SomeProtocol {
func doSomething() {
print(privateVariable)
}
}
>> let s = SomeStruct()
>> s.doSomething()
<< 12
```
-->
## Generics
The access level for a generic type or generic function is
the minimum of the access level of the generic type or function itself
and the access level of any type constraints on its type parameters.
## Type Aliases
Any type aliases you define are treated as distinct types for the purposes of access control.
A type alias can have an access level less than or equal to the access level of the type it aliases.
For example, a private type alias can alias a private, file-private, internal, public, or open type,
but a public type alias can't alias an internal, file-private, or private type.
> Note: This rule also applies to type aliases for associated types used to satisfy protocol conformances.
<!--
- test: `typeAliases`
```swifttest
-> public struct PublicStruct {}
-> internal struct InternalStruct {}
-> private struct PrivateStruct {}
-> public typealias PublicAliasOfPublicType = PublicStruct
-> internal typealias InternalAliasOfPublicType = PublicStruct
-> private typealias PrivateAliasOfPublicType = PublicStruct
-> public typealias PublicAliasOfInternalType = InternalStruct // not allowed
-> internal typealias InternalAliasOfInternalType = InternalStruct
-> private typealias PrivateAliasOfInternalType = InternalStruct
-> public typealias PublicAliasOfPrivateType = PrivateStruct // not allowed
-> internal typealias InternalAliasOfPrivateType = PrivateStruct // not allowed
-> private typealias PrivateAliasOfPrivateType = PrivateStruct
!$ error: type alias cannot be declared public because its underlying type uses an internal type
!! public typealias PublicAliasOfInternalType = InternalStruct // not allowed
!! ^ ~~~~~~~~~~~~~~
!$ note: type declared here
!! internal struct InternalStruct {}
!! ^
!$ error: type alias cannot be declared public because its underlying type uses a private type
!! public typealias PublicAliasOfPrivateType = PrivateStruct // not allowed
!! ^ ~~~~~~~~~~~~~
!$ note: type declared here
!! private struct PrivateStruct {}
!! ^
!$ error: type alias cannot be declared internal because its underlying type uses a private type
!! internal typealias InternalAliasOfPrivateType = PrivateStruct // not allowed
!! ^ ~~~~~~~~~~~~~
!$ note: type declared here
!! private struct PrivateStruct {}
!! ^
```
-->
<!--
This source file is part of the Swift.org open source project
Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-->