3996 lines
142 KiB
Markdown
3996 lines
142 KiB
Markdown
# Declarations
|
||
|
||
Introduce types, operators, variables, and other names and constructs.
|
||
|
||
A *declaration* introduces a new name or construct into your program.
|
||
For example, you use declarations to introduce functions and methods,
|
||
to introduce variables and constants,
|
||
and to define enumeration, structure, class, and protocol types.
|
||
You can also use a declaration to extend the behavior
|
||
of an existing named type and to import symbols into your program that are declared elsewhere.
|
||
|
||
In Swift, most declarations are also definitions in the sense that they're implemented
|
||
or initialized at the same time they're declared. That said, because protocols don't
|
||
implement their members, most protocol members are declarations only. For convenience
|
||
and because the distinction isn't that important in Swift,
|
||
the term *declaration* covers both declarations and definitions.
|
||
|
||
> Grammar of a declaration:
|
||
>
|
||
> *declaration* → *import-declaration* \
|
||
> *declaration* → *constant-declaration* \
|
||
> *declaration* → *variable-declaration* \
|
||
> *declaration* → *typealias-declaration* \
|
||
> *declaration* → *function-declaration* \
|
||
> *declaration* → *enum-declaration* \
|
||
> *declaration* → *struct-declaration* \
|
||
> *declaration* → *class-declaration* \
|
||
> *declaration* → *actor-declaration* \
|
||
> *declaration* → *protocol-declaration* \
|
||
> *declaration* → *initializer-declaration* \
|
||
> *declaration* → *deinitializer-declaration* \
|
||
> *declaration* → *extension-declaration* \
|
||
> *declaration* → *subscript-declaration* \
|
||
> *declaration* → *macro-declaration* \
|
||
> *declaration* → *operator-declaration* \
|
||
> *declaration* → *precedence-group-declaration*
|
||
|
||
## Top-Level Code
|
||
|
||
The top-level code in a Swift source file consists of zero or more statements,
|
||
declarations, and expressions.
|
||
By default, variables, constants, and other named declarations that are declared
|
||
at the top-level of a source file are accessible to code
|
||
in every source file that's part of the same module.
|
||
You can override this default behavior
|
||
by marking the declaration with an access-level modifier,
|
||
as described in <doc:Declarations#Access-Control-Levels>.
|
||
|
||
There are two kinds of top-level code:
|
||
top-level declarations and executable top-level code.
|
||
Top-level declarations consist of only declarations,
|
||
and are allowed in all Swift source files.
|
||
Executable top-level code contains statements and expressions,
|
||
not just declarations,
|
||
and is allowed only as the top-level entry point for the program.
|
||
|
||
The Swift code you compile to make an executable
|
||
can contain at most one of the following approaches
|
||
to mark the top-level entry point,
|
||
regardless of how the code is organized into files and modules:
|
||
a file that contains top-level executable code,
|
||
a `main.swift` file,
|
||
the `main` attribute,
|
||
the `NSApplicationMain` attribute,
|
||
or the `UIApplicationMain` attribute.
|
||
|
||
> Grammar of a top-level declaration:
|
||
>
|
||
> *top-level-declaration* → *statements*_?_
|
||
|
||
## Code Blocks
|
||
|
||
A *code block* is used by a variety of declarations and control structures
|
||
to group statements together.
|
||
It has the following form:
|
||
|
||
```swift
|
||
{
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
The *statements* inside a code block include declarations,
|
||
expressions, and other kinds of statements and are executed in order
|
||
of their appearance in source code.
|
||
|
||
<!--
|
||
TR: What exactly are the scope rules for Swift?
|
||
-->
|
||
|
||
<!--
|
||
TODO: Discuss scope. I assume a code block creates a new scope?
|
||
-->
|
||
|
||
> Grammar of a code block:
|
||
>
|
||
> *code-block* → **`{`** *statements*_?_ **`}`**
|
||
|
||
## Import Declaration
|
||
|
||
An *import declaration* lets you access symbols
|
||
that are declared outside the current file.
|
||
The basic form imports the entire module;
|
||
it consists of the `import` keyword followed by a module name:
|
||
|
||
```swift
|
||
import <#module#>
|
||
```
|
||
|
||
Providing more detail limits which symbols are imported ---
|
||
you can specify a specific submodule
|
||
or a specific declaration within a module or submodule.
|
||
When this detailed form is used,
|
||
only the imported symbol
|
||
(and not the module that declares it)
|
||
is made available in the current scope.
|
||
|
||
```swift
|
||
import <#import kind#> <#module#>.<#symbol name#>
|
||
import <#module#>.<#submodule#>
|
||
```
|
||
|
||
<!--
|
||
TODO: Need to add more to this section.
|
||
-->
|
||
|
||
> Grammar of an import declaration:
|
||
>
|
||
> *import-declaration* → *attributes*_?_ **`import`** *import-kind*_?_ *import-path*
|
||
>
|
||
> *import-kind* → **`typealias`** | **`struct`** | **`class`** | **`enum`** | **`protocol`** | **`let`** | **`var`** | **`func`** \
|
||
> *import-path* → *identifier* | *identifier* **`.`** *import-path*
|
||
|
||
## Constant Declaration
|
||
|
||
A *constant declaration* introduces a constant named value into your program.
|
||
Constant declarations are declared using the `let` keyword and have the following form:
|
||
|
||
```swift
|
||
let <#constant name#>: <#type#> = <#expression#>
|
||
```
|
||
|
||
A constant declaration defines an immutable binding between the *constant name*
|
||
and the value of the initializer *expression*;
|
||
after the value of a constant is set, it can't be changed.
|
||
That said, if a constant is initialized with a class object,
|
||
the object itself can change,
|
||
but the binding between the constant name and the object it refers to can't.
|
||
|
||
When a constant is declared at global scope,
|
||
it must be initialized with a value.
|
||
When a constant declaration occurs in the context of a function or method,
|
||
it can be initialized later,
|
||
as long as it's guaranteed to have a value set
|
||
before the first time its value is read.
|
||
If the compiler can prove that the constant's value is never read,
|
||
the constant isn't required to have a value set at all.
|
||
This analysis is called *definite initialization* ---
|
||
the compiler proves that a value is definitely set before being read.
|
||
|
||
> Note:
|
||
> Definite initialization
|
||
> can't construct proofs that require domain knowledge,
|
||
> and its ability to track state across conditionals has a limit.
|
||
> If you can determine that constant always has a value set,
|
||
> but the compiler can't prove this is the case,
|
||
> try simplifying the code paths that set the value,
|
||
> or use a variable declaration instead.
|
||
|
||
<!--
|
||
In the most general case,
|
||
DI reduces to the halting problem,
|
||
as shown by Rice's theorem.
|
||
-->
|
||
|
||
When a constant declaration occurs in the context of a class or structure
|
||
declaration, it's considered a *constant property*.
|
||
Constant declarations aren't computed properties and therefore don't have getters
|
||
or setters.
|
||
|
||
If the *constant name* of a constant declaration is a tuple pattern,
|
||
the name of each item in the tuple is bound to the corresponding value
|
||
in the initializer *expression*.
|
||
|
||
```swift
|
||
let (firstNumber, secondNumber) = (10, 42)
|
||
```
|
||
|
||
<!--
|
||
- test: `constant-decl`
|
||
|
||
```swifttest
|
||
-> let (firstNumber, secondNumber) = (10, 42)
|
||
```
|
||
-->
|
||
|
||
In this example,
|
||
`firstNumber` is a named constant for the value `10`,
|
||
and `secondNumber` is a named constant for the value `42`.
|
||
Both constants can now be used independently:
|
||
|
||
```swift
|
||
print("The first number is \(firstNumber).")
|
||
// Prints "The first number is 10."
|
||
print("The second number is \(secondNumber).")
|
||
// Prints "The second number is 42."
|
||
```
|
||
|
||
<!--
|
||
- test: `constant-decl`
|
||
|
||
```swifttest
|
||
-> print("The first number is \(firstNumber).")
|
||
<- The first number is 10.
|
||
-> print("The second number is \(secondNumber).")
|
||
<- The second number is 42.
|
||
```
|
||
-->
|
||
|
||
The type annotation (`:` *type*) is optional in a constant declaration
|
||
when the type of the *constant name* can be inferred,
|
||
as described in <doc:Types#Type-Inference>.
|
||
|
||
To declare a constant type property,
|
||
mark the declaration with the `static` declaration modifier.
|
||
A constant type property of a class is always implicitly final;
|
||
you can't mark it with the `class` or `final` declaration modifier
|
||
to allow or disallow overriding by subclasses.
|
||
Type properties are discussed in <doc:Properties#Type-Properties>.
|
||
|
||
<!--
|
||
- test: `class-constants-cant-have-class-or-final`
|
||
|
||
```swifttest
|
||
-> class Super { class let x = 10 }
|
||
!$ error: class stored properties not supported in classes; did you mean 'static'?
|
||
!! class Super { class let x = 10 }
|
||
!! ~~~~~ ^
|
||
-> class S { static final let x = 10 }
|
||
!$ error: static declarations are already final
|
||
!! class S { static final let x = 10 }
|
||
!! ^~~~~~
|
||
!!-
|
||
```
|
||
-->
|
||
|
||
For more information about constants and for guidance about when to use them,
|
||
see <doc:TheBasics#Constants-and-Variables> and <doc:Properties#Stored-Properties>.
|
||
|
||
> Grammar of a constant declaration:
|
||
>
|
||
> *constant-declaration* → *attributes*_?_ *declaration-modifiers*_?_ **`let`** *pattern-initializer-list*
|
||
>
|
||
> *pattern-initializer-list* → *pattern-initializer* | *pattern-initializer* **`,`** *pattern-initializer-list* \
|
||
> *pattern-initializer* → *pattern* *initializer*_?_ \
|
||
> *initializer* → **`=`** *expression*
|
||
|
||
## Variable Declaration
|
||
|
||
A *variable declaration* introduces a variable named value into your program
|
||
and is declared using the `var` keyword.
|
||
|
||
Variable declarations have several forms that declare different kinds
|
||
of named, mutable values,
|
||
including stored and computed variables and properties,
|
||
stored variable and property observers, and static variable properties.
|
||
The appropriate form to use depends on
|
||
the scope at which the variable is declared and the kind of variable you intend to declare.
|
||
|
||
> Note: You can also declare properties in the context of a protocol declaration,
|
||
> as described in <doc:Declarations#Protocol-Property-Declaration>.
|
||
|
||
You can override a property in a subclass by marking the subclass's property declaration
|
||
with the `override` declaration modifier, as described in <doc:Inheritance#Overriding>.
|
||
|
||
### Stored Variables and Stored Variable Properties
|
||
|
||
The following form declares a stored variable or stored variable property:
|
||
|
||
```swift
|
||
var <#variable name#>: <#type#> = <#expression#>
|
||
```
|
||
|
||
You define this form of a variable declaration at global scope, the local scope
|
||
of a function, or in the context of a class or structure declaration.
|
||
When a variable declaration of this form is declared at global scope or the local
|
||
scope of a function, it's referred to as a *stored variable*.
|
||
When it's declared in the context of a class or structure declaration,
|
||
it's referred to as a *stored variable property*.
|
||
|
||
The initializer *expression* can't be present in a protocol declaration,
|
||
but in all other contexts, the initializer *expression* is optional.
|
||
That said, if no initializer *expression* is present,
|
||
the variable declaration must include an explicit type annotation (`:` *type*).
|
||
|
||
As with constant declarations,
|
||
if a variable declaration omits the initializer *expression*,
|
||
the variable must have a value set before the first time it is read.
|
||
Also like constant declarations,
|
||
if the *variable name* is a tuple pattern,
|
||
the name of each item in the tuple is bound to the corresponding value
|
||
in the initializer *expression*.
|
||
|
||
As their names suggest, the value of a stored variable or a stored variable property
|
||
is stored in memory.
|
||
|
||
### Computed Variables and Computed Properties
|
||
|
||
The following form declares a computed variable or computed property:
|
||
|
||
```swift
|
||
var <#variable name#>: <#type#> {
|
||
get {
|
||
<#statements#>
|
||
}
|
||
set(<#setter name#>) {
|
||
<#statements#>
|
||
}
|
||
}
|
||
```
|
||
|
||
You define this form of a variable declaration at global scope, the local scope
|
||
of a function, or in the context of a class, structure, enumeration, or extension declaration.
|
||
When a variable declaration of this form is declared at global scope or the local
|
||
scope of a function, it's referred to as a *computed variable*.
|
||
When it's declared in the context of a class,
|
||
structure, or extension declaration,
|
||
it's referred to as a *computed property*.
|
||
|
||
The getter is used to read the value,
|
||
and the setter is used to write the value.
|
||
The setter clause is optional,
|
||
and when only a getter is needed, you can omit both clauses and simply
|
||
return the requested value directly,
|
||
as described in <doc:Properties#Read-Only-Computed-Properties>.
|
||
But if you provide a setter clause, you must also provide a getter clause.
|
||
|
||
The *setter name* and enclosing parentheses is optional.
|
||
If you provide a setter name, it's used as the name of the parameter to the setter.
|
||
If you don't provide a setter name, the default parameter name to the setter is `newValue`,
|
||
as described in <doc:Properties#Shorthand-Setter-Declaration>.
|
||
|
||
Unlike stored named values and stored variable properties,
|
||
the value of a computed named value or a computed property isn't stored in memory.
|
||
|
||
For more information and to see examples of computed properties,
|
||
see <doc:Properties#Computed-Properties>.
|
||
|
||
### Stored Variable Observers and Property Observers
|
||
|
||
You can also declare a stored variable or property with `willSet` and `didSet` observers.
|
||
A stored variable or property declared with observers has the following form:
|
||
|
||
```swift
|
||
var <#variable name#>: <#type#> = <#expression#> {
|
||
willSet(<#setter name#>) {
|
||
<#statements#>
|
||
}
|
||
didSet(<#setter name#>) {
|
||
<#statements#>
|
||
}
|
||
}
|
||
```
|
||
|
||
You define this form of a variable declaration at global scope, the local scope
|
||
of a function, or in the context of a class or structure declaration.
|
||
When a variable declaration of this form is declared at global scope or the local
|
||
scope of a function, the observers are referred to as *stored variable observers*.
|
||
When it's declared in the context of a class or structure declaration,
|
||
the observers are referred to as *property observers*.
|
||
|
||
You can add property observers to any stored property. You can also add property
|
||
observers to any inherited property (whether stored or computed) by overriding
|
||
the property within a subclass, as described in <doc:Inheritance#Overriding-Property-Observers>.
|
||
|
||
The initializer *expression* is optional in the context of a class or structure declaration,
|
||
but required elsewhere. The *type* annotation is optional
|
||
when the type can be inferred from the initializer *expression*.
|
||
This expression is evaluated the first time you read the property's value.
|
||
If you overwrite the property's initial value without reading it,
|
||
this expression is evaluated before the first time you write to the property.
|
||
|
||
<!--
|
||
- test: `overwriting-property-without-writing`
|
||
|
||
```swifttest
|
||
>> func loudConst(_ x: Int) -> Int {
|
||
>> print("initial value:", x)
|
||
>> return x
|
||
>> }
|
||
>> var x = loudConst(10)
|
||
>> x = 20
|
||
>> print("x:", x)
|
||
<< initial value: 10
|
||
<< x: 20
|
||
>> var y = loudConst(100)
|
||
>> print("y:", y)
|
||
<< initial value: 100
|
||
<< y: 100
|
||
```
|
||
-->
|
||
|
||
The `willSet` and `didSet` observers provide a way to observe (and to respond appropriately)
|
||
when the value of a variable or property is being set.
|
||
The observers aren't called when the variable or property
|
||
is first initialized.
|
||
Instead, they're called only when the value is set outside of an initialization context.
|
||
|
||
A `willSet` observer is called just before the value of the variable or property
|
||
is set. The new value is passed to the `willSet` observer as a constant,
|
||
and therefore it can't be changed in the implementation of the `willSet` clause.
|
||
The `didSet` observer is called immediately after the new value is set. In contrast
|
||
to the `willSet` observer, the old value of the variable or property
|
||
is passed to the `didSet` observer in case you still need access to it. That said,
|
||
if you assign a value to a variable or property within its own `didSet` observer clause,
|
||
that new value that you assign will replace the one that was just set and passed to
|
||
the `willSet` observer.
|
||
|
||
The *setter name* and enclosing parentheses in the `willSet` and `didSet` clauses are optional.
|
||
If you provide setter names,
|
||
they're used as the parameter names to the `willSet` and `didSet` observers.
|
||
If you don't provide setter names,
|
||
the default parameter name to the `willSet` observer is `newValue`
|
||
and the default parameter name to the `didSet` observer is `oldValue`.
|
||
|
||
The `didSet` clause is optional when you provide a `willSet` clause.
|
||
Likewise, the `willSet` clause is optional when you provide a `didSet` clause.
|
||
|
||
If the body of the `didSet` observer refers to the old value,
|
||
the getter is called before the observer,
|
||
to make the old value available.
|
||
Otherwise, the new value is stored without calling the superclass's getter.
|
||
The example below shows a computed property that's defined by the superclass
|
||
and overridden by its subclasses to add an observer.
|
||
|
||
```swift
|
||
class Superclass {
|
||
private var xValue = 12
|
||
var x: Int {
|
||
get { print("Getter was called"); return xValue }
|
||
set { print("Setter was called"); xValue = newValue }
|
||
}
|
||
}
|
||
|
||
// This subclass doesn't refer to oldValue in its observer, so the
|
||
// superclass's getter is called only once to print the value.
|
||
class New: Superclass {
|
||
override var x: Int {
|
||
didSet { print("New value \(x)") }
|
||
}
|
||
}
|
||
let new = New()
|
||
new.x = 100
|
||
// Prints "Setter was called".
|
||
// Prints "Getter was called".
|
||
// Prints "New value 100".
|
||
|
||
// This subclass refers to oldValue in its observer, so the superclass's
|
||
// getter is called once before the setter, and again to print the value.
|
||
class NewAndOld: Superclass {
|
||
override var x: Int {
|
||
didSet { print("Old value \(oldValue) - new value \(x)") }
|
||
}
|
||
}
|
||
let newAndOld = NewAndOld()
|
||
newAndOld.x = 200
|
||
// Prints "Getter was called".
|
||
// Prints "Setter was called".
|
||
// Prints "Getter was called".
|
||
// Prints "Old value 12 - new value 200".
|
||
```
|
||
|
||
<!--
|
||
- test: `didSet-calls-superclass-getter`
|
||
|
||
```swifttest
|
||
-> class Superclass {
|
||
private var xValue = 12
|
||
var x: Int {
|
||
get { print("Getter was called"); return xValue }
|
||
set { print("Setter was called"); xValue = newValue }
|
||
}
|
||
}
|
||
|
||
// This subclass doesn't refer to oldValue in its observer, so the
|
||
// superclass's getter is called only once to print the value.
|
||
-> class New: Superclass {
|
||
override var x: Int {
|
||
didSet { print("New value \(x)") }
|
||
}
|
||
}
|
||
let new = New()
|
||
new.x = 100
|
||
<- Setter was called
|
||
<- Getter was called
|
||
<- New value 100
|
||
|
||
// This subclass refers to oldValue in its observer, so the superclass's
|
||
// getter is called once before the setter, and again to print the value.
|
||
-> class NewAndOld: Superclass {
|
||
override var x: Int {
|
||
didSet { print("Old value \(oldValue) - new value \(x)") }
|
||
}
|
||
}
|
||
let newAndOld = NewAndOld()
|
||
newAndOld.x = 200
|
||
<- Getter was called
|
||
<- Setter was called
|
||
<- Getter was called
|
||
<- Old value 12 - new value 200
|
||
```
|
||
-->
|
||
|
||
For more information and to see an example of how to use property observers,
|
||
see <doc:Properties#Property-Observers>.
|
||
|
||
<!--
|
||
- test: `cant-mix-get-set-and-didSet`
|
||
|
||
```swifttest
|
||
>> struct S {
|
||
>> var x: Int {
|
||
>> get { print("S getter"); return 12 }
|
||
>> set { return }
|
||
>> didSet { print("S didSet") }
|
||
>> }
|
||
>> }
|
||
!$ error: 'didSet' cannot be provided together with a getter
|
||
!! didSet { print("S didSet") }
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
### Type Variable Properties
|
||
|
||
To declare a type variable property,
|
||
mark the declaration with the `static` declaration modifier.
|
||
Classes can mark type computed properties with the `class` declaration modifier instead
|
||
to allow subclasses to override the superclass’s implementation.
|
||
Type properties are discussed in <doc:Properties#Type-Properties>.
|
||
|
||
> Grammar of a variable declaration:
|
||
>
|
||
> *variable-declaration* → *variable-declaration-head* *pattern-initializer-list* \
|
||
> *variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *code-block* \
|
||
> *variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *getter-setter-block* \
|
||
> *variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *getter-setter-keyword-block* \
|
||
> *variable-declaration* → *variable-declaration-head* *variable-name* *initializer* *willSet-didSet-block* \
|
||
> *variable-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *initializer*_?_ *willSet-didSet-block*
|
||
>
|
||
> *variable-declaration-head* → *attributes*_?_ *declaration-modifiers*_?_ **`var`** \
|
||
> *variable-name* → *identifier*
|
||
>
|
||
> *getter-setter-block* → *code-block* \
|
||
> *getter-setter-block* → **`{`** *getter-clause* *setter-clause*_?_ **`}`** \
|
||
> *getter-setter-block* → **`{`** *setter-clause* *getter-clause* **`}`** \
|
||
> *getter-clause* → *attributes*_?_ *mutation-modifier*_?_ **`get`** *code-block* \
|
||
> *setter-clause* → *attributes*_?_ *mutation-modifier*_?_ **`set`** *setter-name*_?_ *code-block* \
|
||
> *setter-name* → **`(`** *identifier* **`)`**
|
||
>
|
||
> *getter-setter-keyword-block* → **`{`** *getter-keyword-clause* *setter-keyword-clause*_?_ **`}`** \
|
||
> *getter-setter-keyword-block* → **`{`** *setter-keyword-clause* *getter-keyword-clause* **`}`** \
|
||
> *getter-keyword-clause* → *attributes*_?_ *mutation-modifier*_?_ **`get`** \
|
||
> *setter-keyword-clause* → *attributes*_?_ *mutation-modifier*_?_ **`set`**
|
||
>
|
||
> *willSet-didSet-block* → **`{`** *willSet-clause* *didSet-clause*_?_ **`}`** \
|
||
> *willSet-didSet-block* → **`{`** *didSet-clause* *willSet-clause*_?_ **`}`** \
|
||
> *willSet-clause* → *attributes*_?_ **`willSet`** *setter-name*_?_ *code-block* \
|
||
> *didSet-clause* → *attributes*_?_ **`didSet`** *setter-name*_?_ *code-block*
|
||
|
||
<!--
|
||
NOTE: Type annotations are required for computed properties -- the
|
||
types of those properties aren't computed/inferred.
|
||
-->
|
||
|
||
## Type Alias Declaration
|
||
|
||
A *type alias declaration* introduces a named alias of an existing type into your program.
|
||
Type alias declarations are declared using the `typealias` keyword and have the following form:
|
||
|
||
```swift
|
||
typealias <#name#> = <#existing type#>
|
||
```
|
||
|
||
After a type alias is declared, the aliased *name* can be used
|
||
instead of the *existing type* everywhere in your program.
|
||
The *existing type* can be a named type or a compound type.
|
||
Type aliases don't create new types;
|
||
they simply allow a name to refer to an existing type.
|
||
|
||
A type alias declaration can use generic parameters
|
||
to give a name to an existing generic type. The type alias
|
||
can provide concrete types for some or all of the generic parameters
|
||
of the existing type.
|
||
For example:
|
||
|
||
```swift
|
||
typealias StringDictionary<Value> = Dictionary<String, Value>
|
||
|
||
// The following dictionaries have the same type.
|
||
var dictionary1: StringDictionary<Int> = [:]
|
||
var dictionary2: Dictionary<String, Int> = [:]
|
||
```
|
||
|
||
<!--
|
||
- test: `typealias-with-generic`
|
||
|
||
```swifttest
|
||
-> typealias StringDictionary<Value> = Dictionary<String, Value>
|
||
|
||
// The following dictionaries have the same type.
|
||
-> var dictionary1: StringDictionary<Int> = [:]
|
||
-> var dictionary2: Dictionary<String, Int> = [:]
|
||
```
|
||
-->
|
||
|
||
When a type alias is declared with generic parameters, the constraints on those
|
||
parameters must match exactly the constraints on the existing type's generic parameters.
|
||
For example:
|
||
|
||
```swift
|
||
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
|
||
```
|
||
|
||
<!--
|
||
- test: `typealias-with-generic-constraint`
|
||
|
||
```swifttest
|
||
-> typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
|
||
```
|
||
-->
|
||
|
||
Because the type alias and the existing type can be used interchangeably,
|
||
the type alias can't introduce additional generic constraints.
|
||
|
||
A type alias can forward an existing type's generic parameters
|
||
by omitting all generic parameters from the declaration.
|
||
For example,
|
||
the `Diccionario` type alias declared here
|
||
has the same generic parameters and constraints as `Dictionary`.
|
||
|
||
```swift
|
||
typealias Diccionario = Dictionary
|
||
```
|
||
|
||
<!--
|
||
- test: `typealias-using-shorthand`
|
||
|
||
```swifttest
|
||
-> typealias Diccionario = Dictionary
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
Note that the compiler doesn't currently enforce this. For example, this works but shouldn't:
|
||
typealias ProvidingMoreSpecificConstraints<T: Comparable & Hashable> = Dictionary<T, Int>
|
||
-->
|
||
|
||
<!--
|
||
Things that shouldn't work:
|
||
typealias NotRedeclaringSomeOfTheGenericParameters = Dictionary<T, String>
|
||
typealias NotRedeclaringAnyOfTheGenericParameters = Dictionary
|
||
typealias NotProvidingTheCorrectConstraints<T> = Dictionary<T, Int>
|
||
typealias ProvidingMoreSpecificConstraints<T: Comparable & Hashable> = Dictionary<T, Int>
|
||
-->
|
||
|
||
Inside a protocol declaration,
|
||
a type alias can give a shorter and more convenient name
|
||
to a type that's used frequently.
|
||
For example:
|
||
|
||
```swift
|
||
protocol Sequence {
|
||
associatedtype Iterator: IteratorProtocol
|
||
typealias Element = Iterator.Element
|
||
}
|
||
|
||
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
|
||
// ...
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `typealias-in-protocol`
|
||
|
||
```swifttest
|
||
-> protocol Sequence {
|
||
associatedtype Iterator: IteratorProtocol
|
||
typealias Element = Iterator.Element
|
||
}
|
||
|
||
-> func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
|
||
// ...
|
||
>> return 9000
|
||
}
|
||
```
|
||
-->
|
||
|
||
Without this type alias,
|
||
the `sum` function would have to refer to the associated type
|
||
as `T.Iterator.Element` instead of `T.Element`.
|
||
|
||
See also <doc:Declarations#Protocol-Associated-Type-Declaration>.
|
||
|
||
> Grammar of a type alias declaration:
|
||
>
|
||
> *typealias-declaration* → *attributes*_?_ *access-level-modifier*_?_ **`typealias`** *typealias-name* *generic-parameter-clause*_?_ *typealias-assignment* \
|
||
> *typealias-name* → *identifier* \
|
||
> *typealias-assignment* → **`=`** *type*
|
||
|
||
<!--
|
||
Old grammar:
|
||
typealias-declaration -> typealias-head typealias-assignment
|
||
typealias-head -> ``typealias`` typealias-name type-inheritance-clause-OPT
|
||
typealias-name -> identifier
|
||
typealias-assignment -> ``=`` type
|
||
-->
|
||
|
||
## Function Declaration
|
||
|
||
A *function declaration* introduces a function or method into your program.
|
||
A function declared in the context of class, structure, enumeration, or protocol
|
||
is referred to as a *method*.
|
||
Function declarations are declared using the `func` keyword and have the following form:
|
||
|
||
```swift
|
||
func <#function name#>(<#parameters#>) -> <#return type#> {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
If the function has a return type of `Void`,
|
||
the return type can be omitted as follows:
|
||
|
||
```swift
|
||
func <#function name#>(<#parameters#>) {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
The type of each parameter must be included ---
|
||
it can't be inferred.
|
||
If you write `inout` in front of a parameter's type,
|
||
the parameter can be modified inside the scope of the function.
|
||
In-out parameters are discussed in detail
|
||
in <doc:Declarations#In-Out-Parameters>, below.
|
||
|
||
A function declaration whose *statements*
|
||
include only a single expression
|
||
is understood to return the value of that expression.
|
||
This implicit return syntax is considered
|
||
only when the expression's type and the function's return type
|
||
aren't `Void`
|
||
and aren't an enumeration like `Never` that doesn't have any cases.
|
||
|
||
<!--
|
||
As of Swift 5.3,
|
||
the only way to make an uninhabited type is to create an empty enum,
|
||
so just say that directly instead of using & defining the compiler jargon.
|
||
-->
|
||
|
||
Functions can return multiple values using a tuple type
|
||
as the return type of the function.
|
||
|
||
<!--
|
||
TODO: ^-- Add some more here.
|
||
-->
|
||
|
||
A function definition can appear inside another function declaration.
|
||
This kind of function is known as a *nested function*.
|
||
|
||
A nested function is nonescaping if it captures
|
||
a value that's guaranteed to never escape ---
|
||
such as an in-out parameter ---
|
||
or passed as a nonescaping function argument.
|
||
Otherwise, the nested function is an escaping function.
|
||
|
||
For a discussion of nested functions,
|
||
see <doc:Functions#Nested-Functions>.
|
||
|
||
### Parameter Names
|
||
|
||
Function parameters are a comma-separated list
|
||
where each parameter has one of several forms.
|
||
The order of arguments in a function call
|
||
must match the order of parameters in the function's declaration.
|
||
The simplest entry in a parameter list has the following form:
|
||
|
||
```swift
|
||
<#parameter name#>: <#parameter type#>
|
||
```
|
||
|
||
A parameter has a name,
|
||
which is used within the function body,
|
||
as well as an argument label,
|
||
which is used when calling the function or method.
|
||
By default,
|
||
parameter names are also used as argument labels.
|
||
For example:
|
||
|
||
```swift
|
||
func f(x: Int, y: Int) -> Int { return x + y }
|
||
f(x: 1, y: 2) // both x and y are labeled
|
||
```
|
||
|
||
<!--
|
||
- test: `default-parameter-names`
|
||
|
||
```swifttest
|
||
-> func f(x: Int, y: Int) -> Int { return x + y }
|
||
>> let r0 =
|
||
-> f(x: 1, y: 2) // both x and y are labeled
|
||
>> assert(r0 == 3)
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
Rewrite the above to avoid bare expressions.
|
||
Tracking bug is <rdar://problem/35301593>
|
||
-->
|
||
|
||
You can override the default behavior for argument labels
|
||
with one of the following forms:
|
||
|
||
```swift
|
||
<#argument label#> <#parameter name#>: <#parameter type#>
|
||
_ <#parameter name#>: <#parameter type#>
|
||
```
|
||
|
||
A name before the parameter name
|
||
gives the parameter an explicit argument label,
|
||
which can be different from the parameter name.
|
||
The corresponding argument must use the given argument label
|
||
in function or method calls.
|
||
|
||
An underscore (`_`) before a parameter name
|
||
suppresses the argument label.
|
||
The corresponding argument must have no label in function or method calls.
|
||
|
||
```swift
|
||
func repeatGreeting(_ greeting: String, count n: Int) { /* Greet n times */ }
|
||
repeatGreeting("Hello, world!", count: 2) // count is labeled, greeting is not
|
||
```
|
||
|
||
<!--
|
||
- test: `overridden-parameter-names`
|
||
|
||
```swifttest
|
||
-> func repeatGreeting(_ greeting: String, count n: Int) { /* Greet n times */ }
|
||
-> repeatGreeting("Hello, world!", count: 2) // count is labeled, greeting is not
|
||
```
|
||
-->
|
||
|
||
### Parameter Modifiers
|
||
|
||
A *parameter modifier* changes how an argument is passed to the function.
|
||
|
||
```swift
|
||
<#argument label#> <#parameter name#>: <#parameter modifier#> <#parameter type#>
|
||
```
|
||
|
||
To use a parameter modifier,
|
||
write `inout`, `borrowing`, or `consuming`
|
||
before the argument's type.
|
||
|
||
```swift
|
||
func someFunction(a: inout A, b: consuming B, c: C) { ... }
|
||
```
|
||
|
||
#### In-Out Parameters
|
||
|
||
By default, function arguments in Swift are passed by value:
|
||
Any changes made within the function are not visible in the caller.
|
||
To make an in-out parameter instead,
|
||
you apply the `inout` parameter modifier.
|
||
|
||
```swift
|
||
func someFunction(a: inout Int) {
|
||
a += 1
|
||
}
|
||
```
|
||
|
||
When calling a function that includes in-out parameters,
|
||
the in-out argument must be prefixed with an ampersand (`&`)
|
||
to mark that the function call can change the argument's value.
|
||
|
||
```swift
|
||
var x = 7
|
||
someFunction(&x)
|
||
print(x) // Prints "8"
|
||
```
|
||
|
||
In-out parameters are passed as follows:
|
||
|
||
1. When the function is called,
|
||
the value of the argument is copied.
|
||
2. In the body of the function,
|
||
the copy is modified.
|
||
3. When the function returns,
|
||
the copy's value is assigned to the original argument.
|
||
|
||
This behavior is known as *copy-in copy-out*
|
||
or *call by value result*.
|
||
For example,
|
||
when a computed property or a property with observers
|
||
is passed as an in-out parameter,
|
||
its getter is called as part of the function call
|
||
and its setter is called as part of the function return.
|
||
|
||
As an optimization,
|
||
when the argument is a value stored at a physical address in memory,
|
||
the same memory location is used both inside and outside the function body.
|
||
The optimized behavior is known as *call by reference*;
|
||
it satisfies all of the requirements
|
||
of the copy-in copy-out model
|
||
while removing the overhead of copying.
|
||
Write your code using the model given by copy-in copy-out,
|
||
without depending on the call-by-reference optimization,
|
||
so that it behaves correctly with or without the optimization.
|
||
|
||
Within a function, don't access a value that was passed as an in-out argument,
|
||
even if the original value is available in the current scope.
|
||
Accessing the original is a simultaneous access of the value,
|
||
which violates memory exclusivity.
|
||
|
||
```swift
|
||
var someValue: Int
|
||
func someFunction(a: inout Int) {
|
||
a += someValue
|
||
}
|
||
|
||
// Error: This causes a runtime exclusivity violation
|
||
someFunction(&someValue)
|
||
```
|
||
|
||
For the same reason,
|
||
you can't pass the same value to multiple in-out parameters.
|
||
|
||
```swift
|
||
var someValue: Int
|
||
func someFunction(a: inout Int, b: inout Int) {
|
||
a += b
|
||
b += 1
|
||
}
|
||
|
||
// Error: Cannot pass the same value to multiple in-out parameters
|
||
someFunction(&someValue, &someValue)
|
||
```
|
||
|
||
For more information about memory safety and memory exclusivity,
|
||
see <doc:MemorySafety>.
|
||
|
||
<!--
|
||
When the call-by-reference optimization is in play,
|
||
it would happen to do what you want.
|
||
But you still shouldn't do that --
|
||
as noted above, you're not allowed to depend on
|
||
behavioral differences that happen because of call by reference.
|
||
-->
|
||
|
||
A closure or nested function
|
||
that captures an in-out parameter must be nonescaping.
|
||
If you need to capture an in-out parameter
|
||
without mutating it,
|
||
use a capture list to explicitly capture the parameter immutably.
|
||
|
||
```swift
|
||
func someFunction(a: inout Int) -> () -> Int {
|
||
return { [a] in return a + 1 }
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `explicit-capture-for-inout`
|
||
|
||
```swifttest
|
||
-> func someFunction(a: inout Int) -> () -> Int {
|
||
return { [a] in return a + 1 }
|
||
}
|
||
>> class C { var x = 100 }
|
||
>> let c = C()
|
||
>> let f = someFunction(a: &c.x)
|
||
>> c.x = 200
|
||
>> let r = f()
|
||
>> print(r, r == c.x)
|
||
<< 101 false
|
||
```
|
||
-->
|
||
|
||
If you need to capture and mutate an in-out parameter,
|
||
use an explicit local copy,
|
||
such as in multithreaded code that ensures
|
||
all mutation has finished before the function returns.
|
||
|
||
```swift
|
||
func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
|
||
// Make a local copy and manually copy it back.
|
||
var localX = x
|
||
defer { x = localX }
|
||
|
||
// Operate on localX asynchronously, then wait before returning.
|
||
queue.async { someMutatingOperation(&localX) }
|
||
queue.sync {}
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `cant-pass-inout-aliasing`
|
||
|
||
```swifttest
|
||
>> import Dispatch
|
||
>> func someMutatingOperation(_ a: inout Int) {}
|
||
-> func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
|
||
// Make a local copy and manually copy it back.
|
||
var localX = x
|
||
defer { x = localX }
|
||
|
||
// Operate on localX asynchronously, then wait before returning.
|
||
queue.async { someMutatingOperation(&localX) }
|
||
queue.sync {}
|
||
}
|
||
```
|
||
-->
|
||
|
||
For more discussion and examples of in-out parameters,
|
||
see <doc:Functions#In-Out-Parameters>.
|
||
|
||
<!--
|
||
- test: `escaping-cant-capture-inout`
|
||
|
||
```swifttest
|
||
-> func outer(a: inout Int) -> () -> Void {
|
||
func inner() {
|
||
a += 1
|
||
}
|
||
return inner
|
||
}
|
||
!$ error: escaping local function captures 'inout' parameter 'a'
|
||
!! return inner
|
||
!! ^
|
||
!$ note: parameter 'a' is declared 'inout'
|
||
!! func outer(a: inout Int) -> () -> Void {
|
||
!! ^
|
||
!$ note: captured here
|
||
!! a += 1
|
||
!! ^
|
||
-> func closure(a: inout Int) -> () -> Void {
|
||
return { a += 1 }
|
||
}
|
||
!$ error: escaping closure captures 'inout' parameter 'a'
|
||
!! return { a += 1 }
|
||
!! ^
|
||
!$ note: parameter 'a' is declared 'inout'
|
||
!! func closure(a: inout Int) -> () -> Void {
|
||
!! ^
|
||
!$ note: captured here
|
||
!! return { a += 1 }
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
#### Borrowing and Consuming Parameters
|
||
|
||
By default, Swift uses a set of rules
|
||
to automatically manage object lifetime across function calls,
|
||
copying values when required.
|
||
The default rules are designed to minimize overhead in most cases ---
|
||
if you want more specific control,
|
||
you can apply the `borrowing` or `consuming` parameter modifier.
|
||
In this case,
|
||
use `copy` to explicitly mark copy operations.
|
||
In addition,
|
||
values of a noncopyable type must be passed as either borrowing or consuming.
|
||
|
||
Regardless of whether you use the default rules,
|
||
Swift guarantees that object lifetime and
|
||
ownership are correctly managed in all cases.
|
||
These parameter modifiers impact only the relative efficiency
|
||
of particular usage patterns, not correctness.
|
||
|
||
<!--
|
||
TODO: Describe the default rules.
|
||
Essentially, inits and property setters are consuming,
|
||
and everything else is borrowing.
|
||
Where are copies implicitly inserted?
|
||
-->
|
||
|
||
The `borrowing` modifier indicates that the function
|
||
does not keep the parameter's value.
|
||
In this case, the caller maintains ownership of the object
|
||
and the responsibility for the object's lifetime.
|
||
Using `borrowing` minimizes overhead when the function
|
||
uses the object only transiently.
|
||
|
||
```swift
|
||
// `isLessThan` does not keep either argument
|
||
func isLessThan(lhs: borrowing A, rhs: borrowing A) -> Bool {
|
||
...
|
||
}
|
||
```
|
||
|
||
If the function needs to keep the parameter's value
|
||
for example, by storing it in a global variable ---
|
||
you use `copy` to explicitly copy that value.
|
||
|
||
```swift
|
||
// As above, but this `isLessThan` also wants to record the smallest value
|
||
func isLessThan(lhs: borrowing A, rhs: borrowing A) -> Bool {
|
||
if lhs < storedValue {
|
||
storedValue = copy lhs
|
||
} else if rhs < storedValue {
|
||
storedValue = copy rhs
|
||
}
|
||
return lhs < rhs
|
||
}
|
||
```
|
||
|
||
Conversely,
|
||
the `consuming` parameter modifier indicates
|
||
that the function takes ownership of the value,
|
||
accepting responsibility for either storing or destroying it
|
||
before the function returns.
|
||
|
||
```swift
|
||
// `store` keeps its argument, so mark it `consuming`
|
||
func store(a: consuming A) {
|
||
someGlobalVariable = a
|
||
}
|
||
```
|
||
|
||
Using `consuming` minimizes overhead when the caller no longer
|
||
needs to use the object after the function call.
|
||
|
||
```swift
|
||
// Usually, this is the last thing you do with a value
|
||
store(a: value)
|
||
```
|
||
|
||
If you keep using a copyable object after the function call,
|
||
the compiler automatically makes a copy of that object
|
||
before the function call.
|
||
|
||
```swift
|
||
// The compiler inserts an implicit copy here
|
||
store(a: someValue) // This function consumes someValue
|
||
print(someValue) // This uses the copy of someValue
|
||
```
|
||
|
||
Unlike `inout`, neither `borrowing` nor
|
||
`consuming` parameters require any special
|
||
notation when you call the function:
|
||
|
||
```swift
|
||
func someFunction(a: borrowing A, b: consuming B) { ... }
|
||
|
||
someFunction(a: someA, b: someB)
|
||
```
|
||
|
||
The explicit use of either `borrowing` or `consuming`
|
||
indicates your intention to more tightly control
|
||
the overhead of runtime ownership management.
|
||
Because copies can cause unexpected runtime ownership
|
||
operations,
|
||
parameters marked with either of these
|
||
modifiers cannot be copied unless you
|
||
use an explicit `copy` keyword:
|
||
|
||
```swift
|
||
func borrowingFunction1(a: borrowing A) {
|
||
// Error: Cannot implicitly copy a
|
||
// This assignment requires a copy because
|
||
// `a` is only borrowed from the caller.
|
||
someGlobalVariable = a
|
||
}
|
||
|
||
func borrowingFunction2(a: borrowing A) {
|
||
// OK: Explicit copying works
|
||
someGlobalVariable = copy a
|
||
}
|
||
|
||
func consumingFunction1(a: consuming A) {
|
||
// Error: Cannot implicitly copy a
|
||
// This assignment requires a copy because
|
||
// of the following `print`
|
||
someGlobalVariable = a
|
||
print(a)
|
||
}
|
||
|
||
func consumingFunction2(a: consuming A) {
|
||
// OK: Explicit copying works regardless
|
||
someGlobalVariable = copy a
|
||
print(a)
|
||
}
|
||
|
||
func consumingFunction3(a: consuming A) {
|
||
// OK: No copy needed here because this is the last use
|
||
someGlobalVariable = a
|
||
}
|
||
```
|
||
|
||
<!--
|
||
TODO: `borrowing` and `consuming` keywords with noncopyable argument types
|
||
-->
|
||
<!--
|
||
TODO: Any change of parameter modifier is ABI-breaking
|
||
-->
|
||
|
||
### Special Kinds of Parameters
|
||
|
||
Parameters can be ignored,
|
||
take a variable number of values,
|
||
and provide default values
|
||
using the following forms:
|
||
|
||
```swift
|
||
_ : <#parameter type#>
|
||
<#parameter name#>: <#parameter type#>...
|
||
<#parameter name#>: <#parameter type#> = <#default argument value#>
|
||
```
|
||
|
||
An underscore (`_`) parameter
|
||
is explicitly ignored and can't be accessed within the body of the function.
|
||
|
||
A parameter with a base type name followed immediately by three dots (`...`)
|
||
is understood as a variadic parameter.
|
||
A parameter that immediately follows a variadic parameter
|
||
must have an argument label.
|
||
A function can have multiple variadic parameters.
|
||
A variadic parameter is treated as an array that contains elements of the base type name.
|
||
For example, the variadic parameter `Int...` is treated as `[Int]`.
|
||
For an example that uses a variadic parameter,
|
||
see <doc:Functions#Variadic-Parameters>.
|
||
|
||
A parameter with an equal sign (`=`) and an expression after its type
|
||
is understood to have a default value of the given expression.
|
||
The given expression is evaluated when the function is called.
|
||
If the parameter is omitted when calling the function,
|
||
the default value is used instead.
|
||
|
||
```swift
|
||
func f(x: Int = 42) -> Int { return x }
|
||
f() // Valid, uses default value
|
||
f(x: 7) // Valid, uses the value provided
|
||
f(7) // Invalid, missing argument label
|
||
```
|
||
|
||
<!--
|
||
- test: `default-args-and-labels`
|
||
|
||
```swifttest
|
||
-> func f(x: Int = 42) -> Int { return x }
|
||
>> let _ =
|
||
-> f() // Valid, uses default value
|
||
>> let _ =
|
||
-> f(x: 7) // Valid, uses the value provided
|
||
>> let _ =
|
||
-> f(7) // Invalid, missing argument label
|
||
!$ error: missing argument label 'x:' in call
|
||
!! f(7) // Invalid, missing argument label
|
||
!! ^
|
||
!! x:
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
Rewrite the above to avoid discarding the function's return value.
|
||
Tracking bug is <rdar://problem/35301593>
|
||
-->
|
||
|
||
<!--
|
||
- test: `default-args-evaluated-at-call-site`
|
||
|
||
```swifttest
|
||
-> func shout() -> Int {
|
||
print("evaluated")
|
||
return 10
|
||
}
|
||
-> func foo(x: Int = shout()) { print("x is \(x)") }
|
||
-> foo(x: 100)
|
||
<< x is 100
|
||
-> foo()
|
||
<< evaluated
|
||
<< x is 10
|
||
-> foo()
|
||
<< evaluated
|
||
<< x is 10
|
||
```
|
||
-->
|
||
|
||
### Special Kinds of Methods
|
||
|
||
Methods on an enumeration or a structure
|
||
that modify `self` must be marked with the `mutating` declaration modifier.
|
||
|
||
Methods that override a superclass method
|
||
must be marked with the `override` declaration modifier.
|
||
It's a compile-time error to override a method without the `override` modifier
|
||
or to use the `override` modifier on a method
|
||
that doesn't override a superclass method.
|
||
|
||
Methods associated with a type
|
||
rather than an instance of a type
|
||
must be marked with the `static` declaration modifier for enumerations and structures,
|
||
or with either the `static` or `class` declaration modifier for classes.
|
||
A class type method marked with the `class` declaration modifier
|
||
can be overridden by a subclass implementation;
|
||
a class type method marked with `class final` or `static` can't be overridden.
|
||
|
||
<!--
|
||
- test: `overriding-class-methods-err`
|
||
|
||
```swifttest
|
||
-> class S { class final func f() -> Int { return 12 } }
|
||
-> class SS: S { override class func f() -> Int { return 120 } }
|
||
!$ error: class method overrides a 'final' class method
|
||
!! class SS: S { override class func f() -> Int { return 120 } }
|
||
!! ^
|
||
!$ note: overridden declaration is here
|
||
!! class S { class final func f() -> Int { return 12 } }
|
||
!! ^
|
||
-> class S2 { static func f() -> Int { return 12 } }
|
||
-> class SS2: S2 { override static func f() -> Int { return 120 } }
|
||
!$ error: cannot override static method
|
||
!! class SS2: S2 { override static func f() -> Int { return 120 } }
|
||
!! ^
|
||
!$ note: overridden declaration is here
|
||
!! class S2 { static func f() -> Int { return 12 } }
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
- test: `overriding-class-methods`
|
||
|
||
```swifttest
|
||
-> class S3 { class func f() -> Int { return 12 } }
|
||
-> class SS3: S3 { override class func f() -> Int { return 120 } }
|
||
-> print(SS3.f())
|
||
<- 120
|
||
```
|
||
-->
|
||
|
||
### Methods with Special Names
|
||
|
||
Several methods that have special names
|
||
enable syntactic sugar for function call syntax.
|
||
If a type defines one of these methods,
|
||
instances of the type can be used in function call syntax.
|
||
The function call is understood to be a call to
|
||
one of the specially named methods on that instance.
|
||
|
||
A class, structure, or enumeration type
|
||
can support function call syntax
|
||
by defining a `dynamicallyCall(withArguments:)` method
|
||
or a `dynamicallyCall(withKeywordArguments:)` method,
|
||
as described in <doc:Attributes#dynamicCallable>,
|
||
or by defining a call-as-function method, as described below.
|
||
If the type defines
|
||
both a call-as-function method
|
||
and one of the methods used by the `dynamicCallable` attribute,
|
||
the compiler gives preference to the call-as-function method
|
||
in circumstances where either method could be used.
|
||
|
||
The name of a call-as-function method is `callAsFunction()`,
|
||
or another name that begins with `callAsFunction(`
|
||
and adds labeled or unlabeled arguments ---
|
||
for example, `callAsFunction(_:_:)` and `callAsFunction(something:)`
|
||
are also valid call-as-function method names.
|
||
|
||
<!--
|
||
Above, callAsFunction( is in code voice even though
|
||
it's not actually a symbol that exists in the reader's code.
|
||
Per discussion with Chuck, this is the closest typographic convention
|
||
to what we're trying to express here.
|
||
-->
|
||
|
||
The following function calls are equivalent:
|
||
|
||
```swift
|
||
struct CallableStruct {
|
||
var value: Int
|
||
func callAsFunction(_ number: Int, scale: Int) {
|
||
print(scale * (number + value))
|
||
}
|
||
}
|
||
let callable = CallableStruct(value: 100)
|
||
callable(4, scale: 2)
|
||
callable.callAsFunction(4, scale: 2)
|
||
// Both function calls print 208.
|
||
```
|
||
|
||
<!--
|
||
- test: `call-as-function`
|
||
|
||
```swifttest
|
||
-> struct CallableStruct {
|
||
var value: Int
|
||
func callAsFunction(_ number: Int, scale: Int) {
|
||
print(scale * (number + value))
|
||
}
|
||
}
|
||
-> let callable = CallableStruct(value: 100)
|
||
-> callable(4, scale: 2)
|
||
-> callable.callAsFunction(4, scale: 2)
|
||
// Both function calls print 208.
|
||
<< 208
|
||
<< 208
|
||
```
|
||
-->
|
||
|
||
The call-as-function methods
|
||
and the methods from the `dynamicCallable` attribute
|
||
make different trade-offs between
|
||
how much information you encode into the type system
|
||
and how much dynamic behavior is possible at runtime.
|
||
When you declare a call-as-function method,
|
||
you specify the number of arguments,
|
||
and each argument's type and label.
|
||
The `dynamicCallable` attribute's methods specify only the type
|
||
used to hold the array of arguments.
|
||
|
||
Defining a call-as-function method,
|
||
or a method from the `dynamicCallable` attribute,
|
||
doesn't let you use an instance of that type
|
||
as if it were a function in any context other than a function call expression.
|
||
For example:
|
||
|
||
```swift
|
||
let someFunction1: (Int, Int) -> Void = callable(_:scale:) // Error
|
||
let someFunction2: (Int, Int) -> Void = callable.callAsFunction(_:scale:)
|
||
```
|
||
|
||
<!--
|
||
- test: `call-as-function-err`
|
||
|
||
```swifttest
|
||
>> struct CallableStruct {
|
||
>> var value: Int
|
||
>> func callAsFunction(_ number: Int, scale: Int) { }
|
||
>> }
|
||
>> let callable = CallableStruct(value: 100)
|
||
-> let someFunction1: (Int, Int) -> Void = callable(_:scale:) // Error
|
||
-> let someFunction2: (Int, Int) -> Void = callable.callAsFunction(_:scale:)
|
||
>> _ = someFunction1 // suppress unused-constant warning
|
||
>> _ = someFunction2 // suppress unused-constant warning
|
||
!$ error: cannot find 'callable(_:scale:)' in scope
|
||
!! let someFunction1: (Int, Int) -> Void = callable(_:scale:) // Error
|
||
!! ^~~~~~~~~~~~~~~~~~
|
||
```
|
||
-->
|
||
|
||
The `subscript(dynamicMember:)` subscript
|
||
enables syntactic sugar for member lookup,
|
||
as described in <doc:Attributes#dynamicMemberLookup>.
|
||
|
||
### Throwing Functions and Methods
|
||
|
||
Functions and methods that can throw an error must be marked with the `throws` keyword.
|
||
These functions and methods are known as *throwing functions*
|
||
and *throwing methods*.
|
||
They have the following form:
|
||
|
||
```swift
|
||
func <#function name#>(<#parameters#>) throws -> <#return type#> {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
A function that throws a specific error type has the following form:
|
||
|
||
```swift
|
||
func <#function name#>(<#parameters#>) throws(<#error type#>) -> <#return type#> {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
Calls to a throwing function or method must be wrapped in a `try` or `try!` expression
|
||
(that is, in the scope of a `try` or `try!` operator).
|
||
|
||
A function's type includes whether it can throw an error
|
||
and what type of error it throws.
|
||
This subtype relationship means, for example, you can use a nonthrowing function
|
||
in a context where a throwing one is expected.
|
||
For more information about the type of a throwing function,
|
||
see <doc:Types#Function-Type>.
|
||
For examples of working with errors that have explicit types,
|
||
see <doc:ErrorHandling#Specifying-the-Error-Type>.
|
||
|
||
You can't overload a function based only on whether the function can throw an error.
|
||
That said,
|
||
you can overload a function based on whether a function *parameter* can throw an error.
|
||
|
||
A throwing method can't override a nonthrowing method,
|
||
and a throwing method can't satisfy a protocol requirement for a nonthrowing method.
|
||
That said, a nonthrowing method can override a throwing method,
|
||
and a nonthrowing method can satisfy a protocol requirement for a throwing method.
|
||
|
||
### Rethrowing Functions and Methods
|
||
|
||
A function or method can be declared with the `rethrows` keyword
|
||
to indicate that it throws an error only if one of its function parameters throws an error.
|
||
These functions and methods are known as *rethrowing functions*
|
||
and *rethrowing methods*.
|
||
Rethrowing functions and methods
|
||
must have at least one throwing function parameter.
|
||
|
||
```swift
|
||
func someFunction(callback: () throws -> Void) rethrows {
|
||
try callback()
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `rethrows`
|
||
|
||
```swifttest
|
||
-> func someFunction(callback: () throws -> Void) rethrows {
|
||
try callback()
|
||
}
|
||
```
|
||
-->
|
||
|
||
A rethrowing function or method can contain a `throw` statement
|
||
only inside a `catch` clause.
|
||
This lets you call the throwing function inside a `do`-`catch` statement
|
||
and handle errors in the `catch` clause by throwing a different error.
|
||
In addition,
|
||
the `catch` clause must handle
|
||
only errors thrown by one of the rethrowing function's
|
||
throwing parameters.
|
||
For example, the following is invalid
|
||
because the `catch` clause would handle
|
||
the error thrown by `alwaysThrows()`.
|
||
|
||
```swift
|
||
func alwaysThrows() throws {
|
||
throw SomeError.error
|
||
}
|
||
func someFunction(callback: () throws -> Void) rethrows {
|
||
do {
|
||
try callback()
|
||
try alwaysThrows() // Invalid, alwaysThrows() isn't a throwing parameter
|
||
} catch {
|
||
throw AnotherError.error
|
||
}
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `double-negative-rethrows`
|
||
|
||
```swifttest
|
||
>> enum SomeError: Error { case error }
|
||
>> enum AnotherError: Error { case error }
|
||
-> func alwaysThrows() throws {
|
||
throw SomeError.error
|
||
}
|
||
-> func someFunction(callback: () throws -> Void) rethrows {
|
||
do {
|
||
try callback()
|
||
try alwaysThrows() // Invalid, alwaysThrows() isn't a throwing parameter
|
||
} catch {
|
||
throw AnotherError.error
|
||
}
|
||
}
|
||
!$ error: a function declared 'rethrows' may only throw if its parameter does
|
||
!! throw AnotherError.error
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
- test: `throwing-in-rethrowing-function`
|
||
|
||
```swifttest
|
||
-> enum SomeError: Error { case c, d }
|
||
-> func f1(callback: () throws -> Void) rethrows {
|
||
do {
|
||
try callback()
|
||
} catch {
|
||
throw SomeError.c // OK
|
||
}
|
||
}
|
||
-> func f2(callback: () throws -> Void) rethrows {
|
||
throw SomeError.d // Error
|
||
}
|
||
!$ error: a function declared 'rethrows' may only throw if its parameter does
|
||
!! throw SomeError.d // Error
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
A throwing method can't override a rethrowing method,
|
||
and a throwing method can't satisfy a protocol requirement for a rethrowing method.
|
||
That said, a rethrowing method can override a throwing method,
|
||
and a rethrowing method can satisfy a protocol requirement for a throwing method.
|
||
|
||
An alternative to rethrowing is throwing a specific error type in generic code.
|
||
For example:
|
||
|
||
```swift
|
||
func someFunction<E: Error>(callback: () throws(E) -> Void) throws(E) {
|
||
try callback()
|
||
}
|
||
```
|
||
|
||
This approach to propagating an error
|
||
preserves type information about the error.
|
||
However, unlike marking a function `rethrows`,
|
||
this approach doesn't prevent the function
|
||
from throwing an error of the same type.
|
||
|
||
<!--
|
||
TODO: Revisit the comparison between rethrows and throws(E) above,
|
||
since it seems likely that the latter will generally replace the former.
|
||
|
||
See also rdar://128972373
|
||
-->
|
||
|
||
### Asynchronous Functions and Methods
|
||
|
||
Functions and methods that run asynchronously must be marked with the `async` keyword.
|
||
These functions and methods are known as *asynchronous functions*
|
||
and *asynchronous methods*.
|
||
They have the following form:
|
||
|
||
```swift
|
||
func <#function name#>(<#parameters#>) async -> <#return type#> {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
Calls to an asynchronous function or method
|
||
must be wrapped in an `await` expression ---
|
||
that is, they must be in the scope of an `await` operator.
|
||
|
||
The `async` keyword is part of the function's type,
|
||
and synchronous functions are subtypes of asynchronous functions.
|
||
As a result, you can use a synchronous function
|
||
in a context where an asynchronous function is expected.
|
||
For example,
|
||
you can override an asynchronous method with a synchronous method,
|
||
and a synchronous method can satisfy a protocol requirement
|
||
that requires an asynchronous method.
|
||
|
||
You can overload a function based on whether or not the function is asynchronous.
|
||
At the call site, context determines which overload is used:
|
||
In an asynchronous context, the asynchronous function is used,
|
||
and in a synchronous context, the synchronous function is used.
|
||
|
||
An asynchronous method can't override a synchronous method,
|
||
and an asynchronous method can't satisfy a protocol requirement for a synchronous method.
|
||
That said, a synchronous method can override an asynchronous method,
|
||
and a synchronous method can satisfy a protocol requirement for an asynchronous method.
|
||
|
||
<!--
|
||
- test: `sync-satisfy-async-protocol-requirements`
|
||
|
||
```swifttest
|
||
>> protocol P { func f() async -> Int }
|
||
>> class Super: P {
|
||
>> func f() async -> Int { return 12 }
|
||
>> }
|
||
>> class Sub: Super {
|
||
>> func f() -> Int { return 120 }
|
||
>> }
|
||
```
|
||
-->
|
||
|
||
### Functions that Never Return
|
||
|
||
Swift defines a [`Never`][] type,
|
||
which indicates that a function or method doesn't return to its caller.
|
||
Functions and methods with the `Never` return type are called *nonreturning*.
|
||
Nonreturning functions and methods either cause an irrecoverable error
|
||
or begin a sequence of work that continues indefinitely.
|
||
This means that
|
||
code that would otherwise run immediately after the call is never executed.
|
||
Throwing and rethrowing functions can transfer program control
|
||
to an appropriate `catch` block, even when they're nonreturning.
|
||
|
||
[`Never`]: https://developer.apple.com/documentation/swift/never
|
||
|
||
A nonreturning function or method can be called to conclude the `else` clause
|
||
of a guard statement,
|
||
as discussed in <doc:Statements#Guard-Statement>.
|
||
|
||
You can override a nonreturning method,
|
||
but the new method must preserve its return type and nonreturning behavior.
|
||
|
||
> Grammar of a function declaration:
|
||
>
|
||
> *function-declaration* → *function-head* *function-name* *generic-parameter-clause*_?_ *function-signature* *generic-where-clause*_?_ *function-body*_?_
|
||
>
|
||
> *function-head* → *attributes*_?_ *declaration-modifiers*_?_ **`func`** \
|
||
> *function-name* → *identifier* | *operator*
|
||
>
|
||
> *function-signature* → *parameter-clause* **`async`**_?_ *throws-clause*_?_ *function-result*_?_ \
|
||
> *function-signature* → *parameter-clause* **`async`**_?_ **`rethrows`** *function-result*_?_ \
|
||
> *function-result* → **`->`** *attributes*_?_ *type* \
|
||
> *function-body* → *code-block*
|
||
>
|
||
> *parameter-clause* → **`(`** **`)`** | **`(`** *parameter-list* **`)`** \
|
||
> *parameter-list* → *parameter* | *parameter* **`,`** *parameter-list* \
|
||
> *parameter* → *external-parameter-name*_?_ *local-parameter-name* *parameter-type-annotation* *default-argument-clause*_?_ \
|
||
> *parameter* → *external-parameter-name*_?_ *local-parameter-name* *parameter-type-annotation* \
|
||
> *parameter* → *external-parameter-name*_?_ *local-parameter-name* *parameter-type-annotation* **`...`**
|
||
>
|
||
> *external-parameter-name* → *identifier* \
|
||
> *local-parameter-name* → *identifier* \
|
||
> *parameter-type-annotation* → **`:`** *attributes*_?_ *parameter-modifier*_?_ *type* \
|
||
> *parameter-modifier* → **`inout`** | **`borrowing`** | **`consuming`**
|
||
> *default-argument-clause* → **`=`** *expression*
|
||
|
||
<!--
|
||
NOTE: Code block is optional in the context of a protocol.
|
||
Everywhere else, it's required.
|
||
We could refactor to have a separation between function definition/declaration.
|
||
There's also the low-level "asm name" FFI
|
||
which is a definition and declaration corner case.
|
||
Let's just deal with this difference in prose.
|
||
-->
|
||
|
||
## Enumeration Declaration
|
||
|
||
An *enumeration declaration* introduces a named enumeration type into your program.
|
||
|
||
Enumeration declarations have two basic forms and are declared using the `enum` keyword.
|
||
The body of an enumeration declared using either form contains
|
||
zero or more values --- called *enumeration cases* ---
|
||
and any number of declarations,
|
||
including computed properties,
|
||
instance methods, type methods, initializers, type aliases,
|
||
and even other enumeration, structure, class, and actor declarations.
|
||
Enumeration declarations can't contain deinitializer or protocol declarations.
|
||
|
||
Enumeration types can adopt any number of protocols, but can’t inherit from classes,
|
||
structures, or other enumerations.
|
||
|
||
Unlike classes and structures,
|
||
enumeration types don't have an implicitly provided default initializer;
|
||
all initializers must be declared explicitly. Initializers can delegate
|
||
to other initializers in the enumeration, but the initialization process is complete
|
||
only after an initializer assigns one of the enumeration cases to `self`.
|
||
|
||
Like structures but unlike classes, enumerations are value types;
|
||
instances of an enumeration are copied when assigned to
|
||
variables or constants, or when passed as arguments to a function call.
|
||
For information about value types,
|
||
see <doc:ClassesAndStructures#Structures-and-Enumerations-Are-Value-Types>.
|
||
|
||
You can extend the behavior of an enumeration type with an extension declaration,
|
||
as discussed in <doc:Declarations#Extension-Declaration>.
|
||
|
||
### Enumerations with Cases of Any Type
|
||
|
||
The following form declares an enumeration type that contains
|
||
enumeration cases of any type:
|
||
|
||
```swift
|
||
enum <#enumeration name#>: <#adopted protocols#> {
|
||
case <#enumeration case 1#>
|
||
case <#enumeration case 2#>(<#associated value types#>)
|
||
}
|
||
```
|
||
|
||
Enumerations declared in this form are sometimes called *discriminated unions*
|
||
in other programming languages.
|
||
|
||
In this form, each case block consists of the `case` keyword
|
||
followed by one or more enumeration cases, separated by commas.
|
||
The name of each case must be unique.
|
||
Each case can also specify that it stores values of a given type.
|
||
These types are specified in the *associated value types* tuple,
|
||
immediately following the name of the case.
|
||
|
||
Enumeration cases that store associated values can be used as functions
|
||
that create instances of the enumeration with the specified associated values.
|
||
And just like functions,
|
||
you can get a reference to an enumeration case and apply it later in your code.
|
||
|
||
```swift
|
||
enum Number {
|
||
case integer(Int)
|
||
case real(Double)
|
||
}
|
||
let f = Number.integer
|
||
// f is a function of type (Int) -> Number
|
||
|
||
// Apply f to create an array of Number instances with integer values
|
||
let evenInts: [Number] = [0, 2, 4, 6].map(f)
|
||
```
|
||
|
||
<!--
|
||
- test: `enum-case-as-function`
|
||
|
||
```swifttest
|
||
-> enum Number {
|
||
case integer(Int)
|
||
case real(Double)
|
||
}
|
||
-> let f = Number.integer
|
||
-> // f is a function of type (Int) -> Number
|
||
|
||
-> // Apply f to create an array of Number instances with integer values
|
||
-> let evenInts: [Number] = [0, 2, 4, 6].map(f)
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
No expectation for evenInts because there isn't a good way to spell one.
|
||
Using print() puts a module prefix like tmpabc in front of Number
|
||
so the expectation would need to be a regex (which we don't have),
|
||
and assert() would require Number to conform to Equatable.
|
||
-->
|
||
|
||
For more information and to see examples of cases with associated value types,
|
||
see <doc:Enumerations#Associated-Values>.
|
||
|
||
#### Enumerations with Indirection
|
||
|
||
Enumerations can have a recursive structure,
|
||
that is, they can have cases with associated values
|
||
that are instances of the enumeration type itself.
|
||
However, instances of enumeration types have value semantics,
|
||
which means they have a fixed layout in memory.
|
||
To support recursion,
|
||
the compiler must insert a layer of indirection.
|
||
|
||
To enable indirection for a particular enumeration case,
|
||
mark it with the `indirect` declaration modifier.
|
||
An indirect case must have an associated value.
|
||
|
||
<!--
|
||
TODO The word "enable" is kind of a weasel word.
|
||
Better to have a more concrete discussion of exactly when
|
||
it is and isn't used.
|
||
For example, does "indirect enum { X(Int) } mark X as indirect?
|
||
-->
|
||
|
||
```swift
|
||
enum Tree<T> {
|
||
case empty
|
||
indirect case node(value: T, left: Tree, right: Tree)
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `indirect-enum`
|
||
|
||
```swifttest
|
||
-> enum Tree<T> {
|
||
case empty
|
||
indirect case node(value: T, left: Tree, right: Tree)
|
||
}
|
||
>> let l1 = Tree.node(value: 10, left: Tree.empty, right: Tree.empty)
|
||
>> let l2 = Tree.node(value: 100, left: Tree.empty, right: Tree.empty)
|
||
>> let t = Tree.node(value: 50, left: l1, right: l2)
|
||
```
|
||
-->
|
||
|
||
To enable indirection for all the cases of an enumeration
|
||
that have an associated value,
|
||
mark the entire enumeration with the `indirect` modifier ---
|
||
this is convenient when the enumeration contains many cases
|
||
that would each need to be marked with the `indirect` modifier.
|
||
|
||
An enumeration that's marked with the `indirect` modifier
|
||
can contain a mixture of cases that have associated values and cases those that don't.
|
||
That said,
|
||
it can't contain any cases that are also marked with the `indirect` modifier.
|
||
|
||
<!--
|
||
It really should be an associated value **that includes the enum type**
|
||
but right now the compiler is satisfied with any associated value.
|
||
Alex emailed Joe Groff 2015-07-08 about this.
|
||
-->
|
||
|
||
<!--
|
||
assertion indirect-in-indirect
|
||
|
||
-> indirect enum E { indirect case c(E) }
|
||
!! <REPL Input>:1:19: error: enum case in 'indirect' enum cannot also be 'indirect'
|
||
!! indirect enum E { indirect case c(E) }
|
||
!! ^
|
||
-->
|
||
|
||
<!--
|
||
assertion indirect-without-recursion
|
||
|
||
-> enum E { indirect case c }
|
||
!! <REPL Input>:1:10: error: enum case 'c' without associated value cannot be 'indirect'
|
||
!! enum E { indirect case c }
|
||
!! ^
|
||
|
||
-> enum E1 { indirect case c() } // This is fine, but probably shouldn't be
|
||
-> enum E2 { indirect case c(Int) } // This is fine, but probably shouldn't be
|
||
|
||
-> indirect enum E3 { case x }
|
||
-->
|
||
|
||
### Enumerations with Cases of a Raw-Value Type
|
||
|
||
The following form declares an enumeration type that contains
|
||
enumeration cases of the same basic type:
|
||
|
||
```swift
|
||
enum <#enumeration name#>: <#raw-value type#>, <#adopted protocols#> {
|
||
case <#enumeration case 1#> = <#raw value 1#>
|
||
case <#enumeration case 2#> = <#raw value 2#>
|
||
}
|
||
```
|
||
|
||
In this form, each case block consists of the `case` keyword,
|
||
followed by one or more enumeration cases, separated by commas.
|
||
Unlike the cases in the first form, each case has an underlying
|
||
value, called a *raw value*, of the same basic type.
|
||
The type of these values is specified in the *raw-value type* and must represent an
|
||
integer, floating-point number, string, or single character.
|
||
In particular, the *raw-value type* must conform to the `Equatable` protocol
|
||
and one of the following protocols:
|
||
`ExpressibleByIntegerLiteral` for integer literals,
|
||
`ExpressibleByFloatLiteral` for floating-point literals,
|
||
`ExpressibleByStringLiteral` for string literals that contain any number of characters,
|
||
and `ExpressibleByUnicodeScalarLiteral`
|
||
or `ExpressibleByExtendedGraphemeClusterLiteral` for string literals
|
||
that contain only a single character.
|
||
Each case must have a unique name and be assigned a unique raw value.
|
||
|
||
<!--
|
||
The list of ExpressibleBy... protocols above also appears in LexicalStructure_Literals.
|
||
This list is shorter because these five protocols are explicitly supported in the compiler.
|
||
-->
|
||
|
||
If the raw-value type is specified as `Int`
|
||
and you don't assign a value to the cases explicitly,
|
||
they're implicitly assigned the values `0`, `1`, `2`, and so on.
|
||
Each unassigned case of type `Int` is implicitly assigned a raw value
|
||
that's automatically incremented from the raw value of the previous case.
|
||
|
||
```swift
|
||
enum ExampleEnum: Int {
|
||
case a, b, c = 5, d
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `raw-value-enum`
|
||
|
||
```swifttest
|
||
-> enum ExampleEnum: Int {
|
||
case a, b, c = 5, d
|
||
}
|
||
```
|
||
-->
|
||
|
||
In the above example, the raw value of `ExampleEnum.a` is `0` and the value of
|
||
`ExampleEnum.b` is `1`. And because the value of `ExampleEnum.c` is
|
||
explicitly set to `5`, the value of `ExampleEnum.d` is automatically incremented
|
||
from `5` and is therefore `6`.
|
||
|
||
If the raw-value type is specified as `String`
|
||
and you don't assign values to the cases explicitly,
|
||
each unassigned case is implicitly assigned a string with the same text as the name of that case.
|
||
|
||
```swift
|
||
enum GamePlayMode: String {
|
||
case cooperative, individual, competitive
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `raw-value-enum-implicit-string-values`
|
||
|
||
```swifttest
|
||
-> enum GamePlayMode: String {
|
||
case cooperative, individual, competitive
|
||
}
|
||
```
|
||
-->
|
||
|
||
In the above example, the raw value of `GamePlayMode.cooperative` is `"cooperative"`,
|
||
the raw value of `GamePlayMode.individual` is `"individual"`,
|
||
and the raw value of `GamePlayMode.competitive` is `"competitive"`.
|
||
|
||
Enumerations that have cases of a raw-value type implicitly conform to the
|
||
`RawRepresentable` protocol, defined in the Swift standard library.
|
||
As a result, they have a `rawValue` property
|
||
and a failable initializer with the signature `init?(rawValue: RawValue)`.
|
||
You can use the `rawValue` property to access the raw value of an enumeration case,
|
||
as in `ExampleEnum.b.rawValue`.
|
||
You can also use a raw value to find a corresponding case, if there is one,
|
||
by calling the enumeration's failable initializer,
|
||
as in `ExampleEnum(rawValue: 5)`, which returns an optional case.
|
||
For more information and to see examples of cases with raw-value types,
|
||
see <doc:Enumerations#Raw-Values>.
|
||
|
||
### Accessing Enumeration Cases
|
||
|
||
To reference the case of an enumeration type, use dot (`.`) syntax,
|
||
as in `EnumerationType.enumerationCase`. When the enumeration type can be inferred
|
||
from context, you can omit it (the dot is still required),
|
||
as described in <doc:Enumerations#Enumeration-Syntax>
|
||
and <doc:Expressions#Implicit-Member-Expression>.
|
||
|
||
To check the values of enumeration cases, use a `switch` statement,
|
||
as shown in <doc:Enumerations#Matching-Enumeration-Values-with-a-Switch-Statement>.
|
||
The enumeration type is pattern-matched against the enumeration case patterns
|
||
in the case blocks of the `switch` statement,
|
||
as described in <doc:Patterns#Enumeration-Case-Pattern>.
|
||
|
||
<!--
|
||
FIXME: Or use if-case:
|
||
enum E { case c(Int) }
|
||
let e = E.c(100)
|
||
if case E.c(let i) = e { print(i) }
|
||
// prints 100
|
||
-->
|
||
|
||
<!--
|
||
NOTE: Note that you can require protocol adoption,
|
||
by using a protocol type as the raw-value type,
|
||
but you do need to make it be one of the types
|
||
that support = in order for you to specify the raw values.
|
||
You can have: <#raw-value type, protocol conformance#>.
|
||
UPDATE: You can only have one raw-value type specified.
|
||
I changed the grammar to be more restrictive in light of this.
|
||
-->
|
||
|
||
<!--
|
||
NOTE: Per Doug and Ted, "('->' type)?" isn't part of the grammar.
|
||
We removed it from our grammar, below.
|
||
-->
|
||
|
||
> Grammar of an enumeration declaration:
|
||
>
|
||
> *enum-declaration* → *attributes*_?_ *access-level-modifier*_?_ *union-style-enum* \
|
||
> *enum-declaration* → *attributes*_?_ *access-level-modifier*_?_ *raw-value-style-enum*
|
||
>
|
||
> *union-style-enum* → **`indirect`**_?_ **`enum`** *enum-name* *generic-parameter-clause*_?_ *type-inheritance-clause*_?_ *generic-where-clause*_?_ **`{`** *union-style-enum-members*_?_ **`}`** \
|
||
> *union-style-enum-members* → *union-style-enum-member* *union-style-enum-members*_?_ \
|
||
> *union-style-enum-member* → *declaration* | *union-style-enum-case-clause* | *compiler-control-statement* \
|
||
> *union-style-enum-case-clause* → *attributes*_?_ **`indirect`**_?_ **`case`** *union-style-enum-case-list* \
|
||
> *union-style-enum-case-list* → *union-style-enum-case* | *union-style-enum-case* **`,`** *union-style-enum-case-list* \
|
||
> *union-style-enum-case* → *enum-case-name* *tuple-type*_?_ \
|
||
> *enum-name* → *identifier* \
|
||
> *enum-case-name* → *identifier*
|
||
>
|
||
> *raw-value-style-enum* → **`enum`** *enum-name* *generic-parameter-clause*_?_ *type-inheritance-clause* *generic-where-clause*_?_ **`{`** *raw-value-style-enum-members* **`}`** \
|
||
> *raw-value-style-enum-members* → *raw-value-style-enum-member* *raw-value-style-enum-members*_?_ \
|
||
> *raw-value-style-enum-member* → *declaration* | *raw-value-style-enum-case-clause* | *compiler-control-statement* \
|
||
> *raw-value-style-enum-case-clause* → *attributes*_?_ **`case`** *raw-value-style-enum-case-list* \
|
||
> *raw-value-style-enum-case-list* → *raw-value-style-enum-case* | *raw-value-style-enum-case* **`,`** *raw-value-style-enum-case-list* \
|
||
> *raw-value-style-enum-case* → *enum-case-name* *raw-value-assignment*_?_ \
|
||
> *raw-value-assignment* → **`=`** *raw-value-literal* \
|
||
> *raw-value-literal* → *numeric-literal* | *static-string-literal* | *boolean-literal*
|
||
|
||
<!--
|
||
NOTE: The two types of enums are sufficiently different enough to warrant separating
|
||
the grammar accordingly. ([Contributor 6004] pointed this out in his email.)
|
||
I'm not sure I'm happy with the names I've chosen for two kinds of enums,
|
||
so please let me know if you can think of better names (Tim and Dave are OK with them)!
|
||
I chose union-style-enum, because this kind of enum behaves like a discriminated union,
|
||
not like an ordinary enum type. They're a kind of "sum" type in the language
|
||
of ADTs (Algebraic Data Types). Functional languages, like F# for example,
|
||
actually have both types (discriminated unions and enumeration types),
|
||
because they behave differently. I'm not sure why we've blended them together,
|
||
especially given that they have distinct syntactic declaration requirements
|
||
and they behave differently.
|
||
-->
|
||
|
||
## Structure Declaration
|
||
|
||
A *structure declaration* introduces a named structure type into your program.
|
||
Structure declarations are declared using the `struct` keyword and have the following form:
|
||
|
||
```swift
|
||
struct <#structure name#>: <#adopted protocols#> {
|
||
<#declarations#>
|
||
}
|
||
```
|
||
|
||
The body of a structure contains zero or more *declarations*.
|
||
These *declarations* can include both stored and computed properties,
|
||
type properties, instance methods, type methods, initializers, subscripts,
|
||
type aliases, and even other structure, class, actor, and enumeration declarations.
|
||
Structure declarations can't contain deinitializer or protocol declarations.
|
||
For a discussion and several examples of structures
|
||
that include various kinds of declarations,
|
||
see <doc:ClassesAndStructures>.
|
||
|
||
Structure types can adopt any number of protocols,
|
||
but can't inherit from classes, enumerations, or other structures.
|
||
|
||
There are three ways to create an instance of a previously declared structure:
|
||
|
||
- Call one of the initializers declared within the structure,
|
||
as described in <doc:Initialization#Initializers>.
|
||
- If no initializers are declared,
|
||
call the structure's memberwise initializer,
|
||
as described in <doc:Initialization#Memberwise-Initializers-for-Structure-Types>.
|
||
- If no initializers are declared,
|
||
and all properties of the structure declaration were given initial values,
|
||
call the structure's default initializer,
|
||
as described in <doc:Initialization#Default-Initializers>.
|
||
|
||
The process of initializing a structure's declared properties
|
||
is described in <doc:Initialization>.
|
||
|
||
Properties of a structure instance can be accessed using dot (`.`) syntax,
|
||
as described in <doc:ClassesAndStructures#Accessing-Properties>.
|
||
|
||
Structures are value types; instances of a structure are copied when assigned to
|
||
variables or constants, or when passed as arguments to a function call.
|
||
For information about value types,
|
||
see <doc:ClassesAndStructures#Structures-and-Enumerations-Are-Value-Types>.
|
||
|
||
You can extend the behavior of a structure type with an extension declaration,
|
||
as discussed in <doc:Declarations#Extension-Declaration>.
|
||
|
||
> Grammar of a structure declaration:
|
||
>
|
||
> *struct-declaration* → *attributes*_?_ *access-level-modifier*_?_ **`struct`** *struct-name* *generic-parameter-clause*_?_ *type-inheritance-clause*_?_ *generic-where-clause*_?_ *struct-body* \
|
||
> *struct-name* → *identifier* \
|
||
> *struct-body* → **`{`** *struct-members*_?_ **`}`**
|
||
>
|
||
> *struct-members* → *struct-member* *struct-members*_?_ \
|
||
> *struct-member* → *declaration* | *compiler-control-statement*
|
||
|
||
## Class Declaration
|
||
|
||
A *class declaration* introduces a named class type into your program.
|
||
Class declarations are declared using the `class` keyword and have the following form:
|
||
|
||
```swift
|
||
class <#class name#>: <#superclass#>, <#adopted protocols#> {
|
||
<#declarations#>
|
||
}
|
||
```
|
||
|
||
The body of a class contains zero or more *declarations*.
|
||
These *declarations* can include both stored and computed properties,
|
||
instance methods, type methods, initializers,
|
||
a single deinitializer, subscripts, type aliases,
|
||
and even other class, structure, actor, and enumeration declarations.
|
||
Class declarations can't contain protocol declarations.
|
||
For a discussion and several examples of classes
|
||
that include various kinds of declarations,
|
||
see <doc:ClassesAndStructures>.
|
||
|
||
A class type can inherit from only one parent class, its *superclass*,
|
||
but can adopt any number of protocols.
|
||
The *superclass* appears first after the *class name* and colon,
|
||
followed by any *adopted protocols*.
|
||
Generic classes can inherit from other generic and nongeneric classes,
|
||
but a nongeneric class can inherit only from other nongeneric classes.
|
||
When you write the name of a generic superclass class after the colon,
|
||
you must include the full name of that generic class,
|
||
including its generic parameter clause.
|
||
|
||
As discussed in <doc:Declarations#Initializer-Declaration>,
|
||
classes can have designated and convenience initializers.
|
||
The designated initializer of a class must initialize all of the class's
|
||
declared properties and it must do so before calling any of its superclass's
|
||
designated initializers.
|
||
|
||
A class can override properties, methods, subscripts, and initializers of its superclass.
|
||
Overridden properties, methods, subscripts,
|
||
and designated initializers must be marked with the `override` declaration modifier.
|
||
|
||
<!--
|
||
- test: `designatedInitializersRequireOverride`
|
||
|
||
```swifttest
|
||
-> class C { init() {} }
|
||
-> class D: C { override init() { super.init() } }
|
||
```
|
||
-->
|
||
|
||
To require that subclasses implement a superclass's initializer,
|
||
mark the superclass's initializer with the `required` declaration modifier.
|
||
The subclass's implementation of that initializer
|
||
must also be marked with the `required` declaration modifier.
|
||
|
||
Although properties and methods declared in the *superclass* are inherited by
|
||
the current class, designated initializers declared in the *superclass* are only
|
||
inherited when the subclass meets the conditions described in
|
||
<doc:Initialization#Automatic-Initializer-Inheritance>.
|
||
Swift classes don't inherit from a universal base class.
|
||
|
||
There are two ways to create an instance of a previously declared class:
|
||
|
||
- Call one of the initializers declared within the class,
|
||
as described in <doc:Initialization#Initializers>.
|
||
- If no initializers are declared,
|
||
and all properties of the class declaration were given initial values,
|
||
call the class's default initializer,
|
||
as described in <doc:Initialization#Default-Initializers>.
|
||
|
||
Access properties of a class instance with dot (`.`) syntax,
|
||
as described in <doc:ClassesAndStructures#Accessing-Properties>.
|
||
|
||
Classes are reference types; instances of a class are referred to, rather than copied,
|
||
when assigned to variables or constants, or when passed as arguments to a function call.
|
||
For information about reference types,
|
||
see <doc:ClassesAndStructures#Classes-Are-Reference-Types>.
|
||
|
||
You can extend the behavior of a class type with an extension declaration,
|
||
as discussed in <doc:Declarations#Extension-Declaration>.
|
||
|
||
> Grammar of a class declaration:
|
||
>
|
||
> *class-declaration* → *attributes*_?_ *access-level-modifier*_?_ **`final`**_?_ **`class`** *class-name* *generic-parameter-clause*_?_ *type-inheritance-clause*_?_ *generic-where-clause*_?_ *class-body* \
|
||
> *class-declaration* → *attributes*_?_ **`final`** *access-level-modifier*_?_ **`class`** *class-name* *generic-parameter-clause*_?_ *type-inheritance-clause*_?_ *generic-where-clause*_?_ *class-body* \
|
||
> *class-name* → *identifier* \
|
||
> *class-body* → **`{`** *class-members*_?_ **`}`**
|
||
>
|
||
> *class-members* → *class-member* *class-members*_?_ \
|
||
> *class-member* → *declaration* | *compiler-control-statement*
|
||
|
||
## Actor Declaration
|
||
|
||
An *actor declaration* introduces a named actor type into your program.
|
||
Actor declarations are declared using the `actor` keyword and have the following form:
|
||
|
||
```swift
|
||
actor <#actor name#>: <#adopted protocols#> {
|
||
<#declarations#>
|
||
}
|
||
```
|
||
|
||
The body of an actor contains zero or more *declarations*.
|
||
These *declarations* can include both stored and computed properties,
|
||
instance methods, type methods, initializers,
|
||
a single deinitializer, subscripts, type aliases,
|
||
and even other class, structure, and enumeration declarations.
|
||
For a discussion and several examples of actors
|
||
that include various kinds of declarations,
|
||
see <doc:Concurrency#Actors>.
|
||
|
||
Actor types can adopt any number of protocols,
|
||
but can't inherit from classes, enumerations, structures, or other actors.
|
||
However, an actor that is marked with the `@objc` attribute
|
||
implicitly conforms to the `NSObjectProtocol` protocol
|
||
and is exposed to the Objective-C runtime as a subtype of `NSObject`.
|
||
|
||
There are two ways to create an instance of a previously declared actor:
|
||
|
||
- Call one of the initializers declared within the actor,
|
||
as described in <doc:Initialization#Initializers>.
|
||
- If no initializers are declared,
|
||
and all properties of the actor declaration were given initial values,
|
||
call the actor's default initializer,
|
||
as described in <doc:Initialization#Default-Initializers>.
|
||
|
||
By default, members of an actor are isolated to that actor.
|
||
Code, such as the body of a method or the getter for a property,
|
||
is executed on that actor.
|
||
Code within the actor can interact with them synchronously
|
||
because that code is already running on the same actor,
|
||
but code outside the actor must mark them with `await`
|
||
to indicate that this code is asynchronously running code on another actor.
|
||
Key paths can't refer to isolated members of an actor.
|
||
Actor-isolated stored properties can be passed as in-out parameters
|
||
to synchronous functions,
|
||
but not to asynchronous functions.
|
||
|
||
Actors can also have nonisolated members,
|
||
whose declarations are marked with the `nonisolated` keyword.
|
||
A nonisolated member executes like code outside of the actor:
|
||
It can't interact with any of the actor's isolated state,
|
||
and callers don't mark it with `await` when using it.
|
||
|
||
Members of an actor can be marked with the `@objc` attribute
|
||
only if they are nonisolated or asynchronous.
|
||
|
||
The process of initializing an actor's declared properties
|
||
is described in <doc:Initialization>.
|
||
|
||
Properties of an actor instance can be accessed using dot (`.`) syntax,
|
||
as described in <doc:ClassesAndStructures#Accessing-Properties>.
|
||
|
||
Actors are reference types; instances of an actor are referred to, rather than copied,
|
||
when assigned to variables or constants, or when passed as arguments to a function call.
|
||
For information about reference types,
|
||
see <doc:ClassesAndStructures#Classes-Are-Reference-Types>.
|
||
|
||
You can extend the behavior of an actor type with an extension declaration,
|
||
as discussed in <doc:Declarations#Extension-Declaration>.
|
||
|
||
<!--
|
||
TODO Additional bits from the SE-0306 actors proposal:
|
||
|
||
Partial applications of isolated functions are only permitted
|
||
when the expression is a direct argument
|
||
whose corresponding parameter is non-escaping and non-Sendable.
|
||
-->
|
||
|
||
> Grammar of an actor declaration:
|
||
>
|
||
> *actor-declaration* → *attributes*_?_ *access-level-modifier*_?_ **`actor`** *actor-name* *generic-parameter-clause*_?_ *type-inheritance-clause*_?_ *generic-where-clause*_?_ *actor-body* \
|
||
> *actor-name* → *identifier* \
|
||
> *actor-body* → **`{`** *actor-members*_?_ **`}`**
|
||
>
|
||
> *actor-members* → *actor-member* *actor-members*_?_ \
|
||
> *actor-member* → *declaration* | *compiler-control-statement*
|
||
|
||
## Protocol Declaration
|
||
|
||
A *protocol declaration* introduces a named protocol type into your program.
|
||
Protocol declarations are declared
|
||
using the `protocol` keyword and have the following form:
|
||
|
||
```swift
|
||
protocol <#protocol name#>: <#inherited protocols#> {
|
||
<#protocol member declarations#>
|
||
}
|
||
```
|
||
|
||
Protocol declarations can appear at global scope,
|
||
or nested inside a nongeneric type or nongeneric function.
|
||
|
||
The body of a protocol contains zero or more *protocol member declarations*,
|
||
which describe the conformance requirements that any type adopting the protocol must fulfill.
|
||
In particular, a protocol can declare that conforming types must
|
||
implement certain properties, methods, initializers, and subscripts.
|
||
Protocols can also declare special kinds of type aliases,
|
||
called *associated types*, that can specify relationships
|
||
among the various declarations of the protocol.
|
||
Protocol declarations can't contain
|
||
class, structure, enumeration, or other protocol declarations.
|
||
The *protocol member declarations* are discussed in detail below.
|
||
|
||
Protocol types can inherit from any number of other protocols.
|
||
When a protocol type inherits from other protocols,
|
||
the set of requirements from those other protocols are aggregated,
|
||
and any type that inherits from the current protocol must conform to all those requirements.
|
||
For an example of how to use protocol inheritance,
|
||
see <doc:Protocols#Protocol-Inheritance>.
|
||
|
||
> Note: You can also aggregate the conformance requirements of multiple
|
||
> protocols using protocol composition types,
|
||
> as described in <doc:Types#Protocol-Composition-Type>
|
||
> and <doc:Protocols#Protocol-Composition>.
|
||
|
||
You can add protocol conformance to a previously declared type
|
||
by adopting the protocol in an extension declaration of that type.
|
||
In the extension, you must implement all of the adopted protocol's
|
||
requirements. If the type already implements all of the requirements,
|
||
you can leave the body of the extension declaration empty.
|
||
|
||
By default, types that conform to a protocol must implement all
|
||
properties, methods, and subscripts declared in the protocol.
|
||
That said, you can mark these protocol member declarations with the `optional` declaration modifier
|
||
to specify that their implementation by a conforming type is optional.
|
||
The `optional` modifier can be applied
|
||
only to members that are marked with the `objc` attribute,
|
||
and only to members of protocols that are marked
|
||
with the `objc` attribute. As a result, only class types can adopt and conform
|
||
to a protocol that contains optional member requirements.
|
||
For more information about how to use the `optional` declaration modifier
|
||
and for guidance about how to access optional protocol members ---
|
||
for example, when you're not sure whether a conforming type implements them ---
|
||
see <doc:Protocols#Optional-Protocol-Requirements>.
|
||
|
||
<!--
|
||
TODO: Currently, you can't check for an optional initializer,
|
||
so we're leaving those out of the documentation, even though you can mark
|
||
an initializer with the @optional attribute. It's still being decided by the
|
||
compiler team. Update this section if they decide to make everything work
|
||
properly for optional initializer requirements.
|
||
-->
|
||
|
||
The cases of an enumeration can satisfy
|
||
protocol requirements for type members.
|
||
Specifically,
|
||
an enumeration case without any associated values
|
||
satisfies a protocol requirement for
|
||
a get-only type variable of type `Self`,
|
||
and an enumeration case with associated values
|
||
satisfies a protocol requirement for a function that returns `Self`
|
||
whose parameters and their argument labels
|
||
match the case's associated values.
|
||
For example:
|
||
|
||
```swift
|
||
protocol SomeProtocol {
|
||
static var someValue: Self { get }
|
||
static func someFunction(x: Int) -> Self
|
||
}
|
||
enum MyEnum: SomeProtocol {
|
||
case someValue
|
||
case someFunction(x: Int)
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `enum-case-satisfy-protocol-requirement`
|
||
|
||
```swifttest
|
||
-> protocol SomeProtocol {
|
||
static var someValue: Self { get }
|
||
static func someFunction(x: Int) -> Self
|
||
}
|
||
-> enum MyEnum: SomeProtocol {
|
||
case someValue
|
||
case someFunction(x: Int)
|
||
}
|
||
```
|
||
-->
|
||
|
||
To restrict the adoption of a protocol to class types only,
|
||
include the `AnyObject` protocol in the *inherited protocols*
|
||
list after the colon.
|
||
For example, the following protocol can be adopted only by class types:
|
||
|
||
```swift
|
||
protocol SomeProtocol: AnyObject {
|
||
/* Protocol members go here */
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `protocol-declaration`
|
||
|
||
```swifttest
|
||
-> protocol SomeProtocol: AnyObject {
|
||
/* Protocol members go here */
|
||
}
|
||
```
|
||
-->
|
||
|
||
Any protocol that inherits from a protocol that's marked with the `AnyObject` requirement
|
||
can likewise be adopted only by class types.
|
||
|
||
> Note: If a protocol is marked with the `objc` attribute,
|
||
> the `AnyObject` requirement is implicitly applied to that protocol;
|
||
> there’s no need to mark the protocol with the `AnyObject` requirement explicitly.
|
||
|
||
Protocols are named types, and thus they can appear in all the same places
|
||
in your code as other named types, as discussed in <doc:Protocols#Protocols-as-Types>.
|
||
However,
|
||
you can't construct an instance of a protocol,
|
||
because protocols don't actually provide the implementations for the requirements
|
||
they specify.
|
||
|
||
You can use protocols to declare which methods a delegate of a class or structure
|
||
should implement, as described in <doc:Protocols#Delegation>.
|
||
|
||
> Grammar of a protocol declaration:
|
||
>
|
||
> *protocol-declaration* → *attributes*_?_ *access-level-modifier*_?_ **`protocol`** *protocol-name* *type-inheritance-clause*_?_ *generic-where-clause*_?_ *protocol-body* \
|
||
> *protocol-name* → *identifier* \
|
||
> *protocol-body* → **`{`** *protocol-members*_?_ **`}`**
|
||
>
|
||
> *protocol-members* → *protocol-member* *protocol-members*_?_ \
|
||
> *protocol-member* → *protocol-member-declaration* | *compiler-control-statement*
|
||
>
|
||
> *protocol-member-declaration* → *protocol-property-declaration* \
|
||
> *protocol-member-declaration* → *protocol-method-declaration* \
|
||
> *protocol-member-declaration* → *protocol-initializer-declaration* \
|
||
> *protocol-member-declaration* → *protocol-subscript-declaration* \
|
||
> *protocol-member-declaration* → *protocol-associated-type-declaration* \
|
||
> *protocol-member-declaration* → *typealias-declaration*
|
||
|
||
### Protocol Property Declaration
|
||
|
||
Protocols declare that conforming types must implement a property
|
||
by including a *protocol property declaration*
|
||
in the body of the protocol declaration.
|
||
Protocol property declarations have a special form of a variable
|
||
declaration:
|
||
|
||
```swift
|
||
var <#property name#>: <#type#> { get set }
|
||
```
|
||
|
||
As with other protocol member declarations, these property declarations
|
||
declare only the getter and setter requirements for types
|
||
that conform to the protocol. As a result, you don't implement the getter or setter
|
||
directly in the protocol in which it's declared.
|
||
|
||
The getter and setter requirements can be satisfied by a conforming type in a variety of ways.
|
||
If a property declaration includes both the `get` and `set` keywords,
|
||
a conforming type can implement it with a stored variable property
|
||
or a computed property that's both readable and writeable
|
||
(that is, one that implements both a getter and a setter). However,
|
||
that property declaration can't be implemented as a constant property
|
||
or a read-only computed property. If a property declaration includes
|
||
only the `get` keyword, it can be implemented as any kind of property.
|
||
For examples of conforming types that implement the property requirements of a protocol,
|
||
see <doc:Protocols#Property-Requirements>.
|
||
|
||
To declare a type property requirement in a protocol declaration,
|
||
mark the property declaration with the `static` keyword.
|
||
Structures and enumerations that conform to the protocol
|
||
declare the property with the `static` keyword,
|
||
and classes that conform to the protocol
|
||
declare the property with either the `static` or `class` keyword.
|
||
Extensions that add protocol conformance to a structure, enumeration, or class
|
||
use the same keyword as the type they extend uses.
|
||
Extensions that provide a default implementation for a type property requirement
|
||
use the `static` keyword.
|
||
|
||
<!--
|
||
- test: `protocols-with-type-property-requirements`
|
||
|
||
```swifttest
|
||
-> protocol P { static var x: Int { get } }
|
||
-> protocol P2 { class var x: Int { get } }
|
||
!$ error: class properties are only allowed within classes; use 'static' to declare a requirement fulfilled by either a static or class property
|
||
!! protocol P2 { class var x: Int { get } }
|
||
!! ~~~~~ ^
|
||
!! static
|
||
-> struct S: P { static var x = 10 }
|
||
-> class C1: P { static var x = 20 }
|
||
-> class C2: P { class var x = 30 }
|
||
!$ error: class stored properties not supported in classes; did you mean 'static'?
|
||
!! class C2: P { class var x = 30 }
|
||
!! ~~~~~ ^
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
- test: `protocol-type-property-default-implementation`
|
||
|
||
```swifttest
|
||
-> protocol P { static var x: Int { get } }
|
||
-> extension P { static var x: Int { return 100 } }
|
||
-> struct S1: P { }
|
||
-> print(S1.x)
|
||
<- 100
|
||
-> struct S2: P { static var x = 10 }
|
||
-> print(S2.x)
|
||
<- 10
|
||
```
|
||
-->
|
||
|
||
See also <doc:Declarations#Variable-Declaration>.
|
||
|
||
> Grammar of a protocol property declaration:
|
||
>
|
||
> *protocol-property-declaration* → *variable-declaration-head* *variable-name* *type-annotation* *getter-setter-keyword-block*
|
||
|
||
### Protocol Method Declaration
|
||
|
||
Protocols declare that conforming types must implement a method
|
||
by including a protocol method declaration in the body of the protocol declaration.
|
||
Protocol method declarations have the same form as
|
||
function declarations, with two exceptions: They don't include a function body,
|
||
and you can't provide any default parameter values as part of the function declaration.
|
||
For examples of conforming types that implement the method requirements of a protocol,
|
||
see <doc:Protocols#Method-Requirements>.
|
||
|
||
To declare a class or static method requirement in a protocol declaration,
|
||
mark the method declaration with the `static` declaration modifier.
|
||
Structures and enumerations that conform to the protocol
|
||
declare the method with the `static` keyword,
|
||
and classes that conform to the protocol
|
||
declare the method with either the `static` or `class` keyword.
|
||
Extensions that add protocol conformance to a structure, enumeration, or class
|
||
use the same keyword as the type they extend uses.
|
||
Extensions that provide a default implementation for a type method requirement
|
||
use the `static` keyword.
|
||
|
||
See also <doc:Declarations#Function-Declaration>.
|
||
|
||
<!--
|
||
TODO: Talk about using ``Self`` in parameters and return types.
|
||
-->
|
||
|
||
> Grammar of a protocol method declaration:
|
||
>
|
||
> *protocol-method-declaration* → *function-head* *function-name* *generic-parameter-clause*_?_ *function-signature* *generic-where-clause*_?_
|
||
|
||
### Protocol Initializer Declaration
|
||
|
||
Protocols declare that conforming types must implement an initializer
|
||
by including a protocol initializer declaration in the body of the protocol declaration.
|
||
Protocol initializer declarations have the same form as
|
||
initializer declarations, except they don't include the initializer's body.
|
||
|
||
A conforming type can satisfy a nonfailable protocol initializer requirement
|
||
by implementing a nonfailable initializer or an `init!` failable initializer.
|
||
A conforming type can satisfy a failable protocol initializer requirement
|
||
by implementing any kind of initializer.
|
||
|
||
When a class implements an initializer to satisfy a protocol's initializer requirement,
|
||
the initializer must be marked with the `required` declaration modifier
|
||
if the class isn't already marked with the `final` declaration modifier.
|
||
|
||
See also <doc:Declarations#Initializer-Declaration>.
|
||
|
||
> Grammar of a protocol initializer declaration:
|
||
>
|
||
> *protocol-initializer-declaration* → *initializer-head* *generic-parameter-clause*_?_ *parameter-clause* *throws-clause*_?_ *generic-where-clause*_?_ \
|
||
> *protocol-initializer-declaration* → *initializer-head* *generic-parameter-clause*_?_ *parameter-clause* **`rethrows`** *generic-where-clause*_?_
|
||
|
||
### Protocol Subscript Declaration
|
||
|
||
Protocols declare that conforming types must implement a subscript
|
||
by including a protocol subscript declaration in the body of the protocol declaration.
|
||
Protocol subscript declarations have a special form of a subscript declaration:
|
||
|
||
```swift
|
||
subscript (<#parameters#>) -> <#return type#> { get set }
|
||
```
|
||
|
||
Subscript declarations only declare the minimum getter and setter implementation
|
||
requirements for types that conform to the protocol.
|
||
If the subscript declaration includes both the `get` and `set` keywords,
|
||
a conforming type must implement both a getter and a setter clause.
|
||
If the subscript declaration includes only the `get` keyword,
|
||
a conforming type must implement *at least* a getter clause
|
||
and optionally can implement a setter clause.
|
||
|
||
To declare a static subscript requirement in a protocol declaration,
|
||
mark the subscript declaration with the `static` declaration modifier.
|
||
Structures and enumerations that conform to the protocol
|
||
declare the subscript with the `static` keyword,
|
||
and classes that conform to the protocol
|
||
declare the subscript with either the `static` or `class` keyword.
|
||
Extensions that add protocol conformance to a structure, enumeration, or class
|
||
use the same keyword as the type they extend uses.
|
||
Extensions that provide a default implementation for a static subscript requirement
|
||
use the `static` keyword.
|
||
|
||
See also <doc:Declarations#Subscript-Declaration>.
|
||
|
||
> Grammar of a protocol subscript declaration:
|
||
>
|
||
> *protocol-subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause*_?_ *getter-setter-keyword-block*
|
||
|
||
### Protocol Associated Type Declaration
|
||
|
||
Protocols declare associated types using the `associatedtype` keyword.
|
||
An associated type provides an alias for a type
|
||
that's used as part of a protocol's declaration.
|
||
Associated types are similar to type parameters in generic parameter clauses,
|
||
but they're associated with `Self` in the protocol in which they're declared.
|
||
In that context, `Self` refers to the eventual type that conforms to the protocol.
|
||
For more information and examples,
|
||
see <doc:Generics#Associated-Types>.
|
||
|
||
You use a generic `where` clause in a protocol declaration
|
||
to add constraints to an associated types inherited from another protocol,
|
||
without redeclaring the associated types.
|
||
For example, the declarations of `SubProtocol` below are equivalent:
|
||
|
||
```swift
|
||
protocol SomeProtocol {
|
||
associatedtype SomeType
|
||
}
|
||
|
||
protocol SubProtocolA: SomeProtocol {
|
||
// This syntax produces a warning.
|
||
associatedtype SomeType: Equatable
|
||
}
|
||
|
||
// This syntax is preferred.
|
||
protocol SubProtocolB: SomeProtocol where SomeType: Equatable { }
|
||
```
|
||
|
||
<!--
|
||
- test: `protocol-associatedtype`
|
||
|
||
```swifttest
|
||
-> protocol SomeProtocol {
|
||
associatedtype SomeType
|
||
}
|
||
|
||
-> protocol SubProtocolA: SomeProtocol {
|
||
// This syntax produces a warning.
|
||
associatedtype SomeType: Equatable
|
||
}
|
||
!$ warning: redeclaration of associated type 'SomeType' from protocol 'SomeProtocol' is better expressed as a 'where' clause on the protocol
|
||
!! associatedtype SomeType: Equatable
|
||
!! ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
|
||
!!-
|
||
!$ note: 'SomeType' declared here
|
||
!! associatedtype SomeType
|
||
!! ^
|
||
|
||
// This syntax is preferred.
|
||
-> protocol SubProtocolB: SomeProtocol where SomeType: Equatable { }
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
TODO: Finish writing this section after WWDC.
|
||
-->
|
||
|
||
<!--
|
||
NOTE:
|
||
What are associated types? What are they "associated" with? Is "Self"
|
||
an implicit associated type of every protocol? [...]
|
||
|
||
Here's an initial stab:
|
||
An Associated Type is associated with an implementation of that protocol.
|
||
The protocol declares it, and is defined as part of the protocol's implementation.
|
||
|
||
"The ``Self`` type allows you to refer to the eventual type of ``self``
|
||
(where ``self`` is the type that conforms to the protocol).
|
||
In addition to ``Self``, a protocol's operations often need to refer to types
|
||
that are related to the type of ``Self``, such as a type of data stored in a
|
||
collection or the node and edge types of a graph." Is this still true?
|
||
|
||
-> If we expand the discussion here,
|
||
-> add a link from Types_SelfType
|
||
-> to give more details about Self in protocols.
|
||
|
||
NOTES from Doug:
|
||
At one point, Self was an associated type, but that's the wrong modeling of
|
||
the problem. Self is the stand-in type for the thing that conforms to the
|
||
protocol. It's weird to think of it as an associated type because it's the
|
||
primary thing. It's certainly not an associated type. In many ways, you
|
||
can think of associated types as being parameters that get filled in by the
|
||
conformance of a specific concrete type to that protocol.
|
||
|
||
There's a substitution mapping here. The parameters are associated with
|
||
Self because they're derived from Self. When you have a concrete type that
|
||
conforms to a protocol, it supplies concrete types for Self and all the
|
||
associated types.
|
||
|
||
The associated types are like parameters, but they're associated with Self in
|
||
the protocol. Self is the eventual type of the thing that conforms to the
|
||
protocol -- you have to have a name for it so you can do things with it.
|
||
|
||
We use "associated" in contrast with generic parameters in interfaces in C#.
|
||
The interesting thing there is that they don't have a name like Self for the
|
||
actual type, but you can name any of these independent types. In theory,
|
||
they're often independent but in practice they're often not -- you have an
|
||
interface parameterized on T, where all the uses of the thing are that T are
|
||
the same as Self. Instead of having these independent parameters to an
|
||
interface, we have a named thing (Self) and all these other things that hand
|
||
off of it.
|
||
|
||
Here's a stupid simple way to see the distinction:
|
||
|
||
C#:
|
||
|
||
interface Sequence <Element> {}
|
||
|
||
class String : Sequence <UnicodeScalar>
|
||
class String : Sequence <GraphemeCluster>
|
||
|
||
These are both fine in C#
|
||
|
||
Swift:
|
||
|
||
protocol Sequence { typealias Element }
|
||
|
||
class String : Sequence { typealias Element = ... }
|
||
|
||
Here you have to pick one or the other -- you can't have both.
|
||
-->
|
||
|
||
See also <doc:Declarations#Type-Alias-Declaration>.
|
||
|
||
> Grammar of a protocol associated type declaration:
|
||
>
|
||
> *protocol-associated-type-declaration* → *attributes*_?_ *access-level-modifier*_?_ **`associatedtype`** *typealias-name* *type-inheritance-clause*_?_ *typealias-assignment*_?_ *generic-where-clause*_?_
|
||
|
||
## Initializer Declaration
|
||
|
||
An *initializer declaration* introduces an initializer for a class,
|
||
structure, or enumeration into your program.
|
||
Initializer declarations are declared using the `init` keyword and have
|
||
two basic forms.
|
||
|
||
Structure, enumeration, and class types can have any number of initializers,
|
||
but the rules and associated behavior for class initializers are different.
|
||
Unlike structures and enumerations, classes have two kinds of initializers:
|
||
designated initializers and convenience initializers,
|
||
as described in <doc:Initialization>.
|
||
|
||
The following form declares initializers for structures, enumerations,
|
||
and designated initializers of classes:
|
||
|
||
```swift
|
||
init(<#parameters#>) {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
A designated initializer of a class initializes
|
||
all of the class's properties directly. It can't call any other initializers
|
||
of the same class, and if the class has a superclass, it must call one of
|
||
the superclass's designated initializers.
|
||
If the class inherits any properties from its superclass, one of the
|
||
superclass's designated initializers must be called before any of these
|
||
properties can be set or modified in the current class.
|
||
|
||
Designated initializers can be declared in the context of a class declaration only
|
||
and therefore can't be added to a class using an extension declaration.
|
||
|
||
Initializers in structures and enumerations can call other declared initializers
|
||
to delegate part or all of the initialization process.
|
||
|
||
To declare convenience initializers for a class,
|
||
mark the initializer declaration with the `convenience` declaration modifier.
|
||
|
||
```swift
|
||
convenience init(<#parameters#>) {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
Convenience initializers can delegate the initialization process to another
|
||
convenience initializer or to one of the class's designated initializers.
|
||
That said, the initialization processes must end with a call to a designated
|
||
initializer that ultimately initializes the class's properties.
|
||
Convenience initializers can't call a superclass's initializers.
|
||
|
||
You can mark designated and convenience initializers with the `required`
|
||
declaration modifier to require that every subclass implement the initializer.
|
||
A subclass’s implementation of that initializer
|
||
must also be marked with the `required` declaration modifier.
|
||
|
||
By default, initializers declared in a superclass
|
||
aren't inherited by subclasses.
|
||
That said, if a subclass initializes all of its stored properties with default values
|
||
and doesn't define any initializers of its own,
|
||
it inherits all of the superclass's initializers.
|
||
If the subclass overrides all of the superclass’s designated initializers,
|
||
it inherits the superclass’s convenience initializers.
|
||
|
||
As with methods, properties, and subscripts,
|
||
you need to mark overridden designated initializers with the `override` declaration modifier.
|
||
|
||
> Note: If you mark an initializer with the `required` declaration modifier,
|
||
> you don't also mark the initializer with the `override` modifier
|
||
> when you override the required initializer in a subclass.
|
||
|
||
Just like functions and methods, initializers can throw or rethrow errors.
|
||
And just like functions and methods,
|
||
you use the `throws` or `rethrows` keyword after an initializer's parameters
|
||
to indicate the appropriate behavior.
|
||
Likewise, initializers can be asynchronous,
|
||
and you use the `async` keyword to indicate this.
|
||
|
||
To see examples of initializers in various type declarations,
|
||
see <doc:Initialization>.
|
||
|
||
### Failable Initializers
|
||
|
||
A *failable initializer* is a type of initializer that produces an optional instance
|
||
or an implicitly unwrapped optional instance of the type the initializer is declared on.
|
||
As a result, a failable initializer can return `nil` to indicate that initialization failed.
|
||
|
||
To declare a failable initializer that produces an optional instance,
|
||
append a question mark to the `init` keyword in the initializer declaration (`init?`).
|
||
To declare a failable initializer that produces an implicitly unwrapped optional instance,
|
||
append an exclamation point instead (`init!`). The example below shows an `init?`
|
||
failable initializer that produces an optional instance of a structure.
|
||
|
||
```swift
|
||
struct SomeStruct {
|
||
let property: String
|
||
// produces an optional instance of 'SomeStruct'
|
||
init?(input: String) {
|
||
if input.isEmpty {
|
||
// discard 'self' and return 'nil'
|
||
return nil
|
||
}
|
||
property = input
|
||
}
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `failable`
|
||
|
||
```swifttest
|
||
-> struct SomeStruct {
|
||
let property: String
|
||
// produces an optional instance of 'SomeStruct'
|
||
init?(input: String) {
|
||
if input.isEmpty {
|
||
// discard 'self' and return 'nil'
|
||
return nil
|
||
}
|
||
property = input
|
||
}
|
||
}
|
||
```
|
||
-->
|
||
|
||
You call an `init?` failable initializer in the same way that you call a nonfailable initializer,
|
||
except that you must deal with the optionality of the result.
|
||
|
||
```swift
|
||
if let actualInstance = SomeStruct(input: "Hello") {
|
||
// do something with the instance of 'SomeStruct'
|
||
} else {
|
||
// initialization of 'SomeStruct' failed and the initializer returned 'nil'
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `failable`
|
||
|
||
```swifttest
|
||
-> if let actualInstance = SomeStruct(input: "Hello") {
|
||
// do something with the instance of 'SomeStruct'
|
||
>> _ = actualInstance
|
||
} else {
|
||
// initialization of 'SomeStruct' failed and the initializer returned 'nil'
|
||
}
|
||
```
|
||
-->
|
||
|
||
A failable initializer can return `nil`
|
||
at any point in the implementation of the initializer's body.
|
||
|
||
A failable initializer can delegate to any kind of initializer.
|
||
A nonfailable initializer can delegate to another nonfailable initializer
|
||
or to an `init!` failable initializer.
|
||
A nonfailable initializer can delegate to an `init?` failable initializer
|
||
by force-unwrapping the result of the superclass's initializer ---
|
||
for example, by writing `super.init()!`.
|
||
|
||
Initialization failure propagates through initializer delegation.
|
||
Specifically,
|
||
if a failable initializer delegates to an initializer that fails and returns `nil`,
|
||
then the initializer that delegated also fails and implicitly returns `nil`.
|
||
If a nonfailable initializer delegates to an `init!` failable initializer that fails and returns `nil`,
|
||
then a runtime error is raised
|
||
(as if you used the `!` operator to unwrap an optional that has a `nil` value).
|
||
|
||
A failable designated initializer can be overridden in a subclass
|
||
by any kind of designated initializer.
|
||
A nonfailable designated initializer can be overridden in a subclass
|
||
by a nonfailable designated initializer only.
|
||
|
||
For more information and to see examples of failable initializers,
|
||
see <doc:Initialization#Failable-Initializers>.
|
||
|
||
> Grammar of an initializer declaration:
|
||
>
|
||
> *initializer-declaration* → *initializer-head* *generic-parameter-clause*_?_ *parameter-clause* **`async`**_?_ *throws-clause*_?_ *generic-where-clause*_?_ *initializer-body* \
|
||
> *initializer-declaration* → *initializer-head* *generic-parameter-clause*_?_ *parameter-clause* **`async`**_?_ **`rethrows`** *generic-where-clause*_?_ *initializer-body* \
|
||
> *initializer-head* → *attributes*_?_ *declaration-modifiers*_?_ **`init`** \
|
||
> *initializer-head* → *attributes*_?_ *declaration-modifiers*_?_ **`init`** **`?`** \
|
||
> *initializer-head* → *attributes*_?_ *declaration-modifiers*_?_ **`init`** **`!`** \
|
||
> *initializer-body* → *code-block*
|
||
|
||
## Deinitializer Declaration
|
||
|
||
A *deinitializer declaration* declares a deinitializer for a class type.
|
||
Deinitializers take no parameters and have the following form:
|
||
|
||
```swift
|
||
deinit {
|
||
<#statements#>
|
||
}
|
||
```
|
||
|
||
A deinitializer is called automatically when there are no longer any references
|
||
to a class object, just before the class object is deallocated.
|
||
A deinitializer can be declared only in the body of a class declaration ---
|
||
but not in an extension of a class ---
|
||
and each class can have at most one.
|
||
|
||
A subclass inherits its superclass's deinitializer,
|
||
which is implicitly called just before the subclass object is deallocated.
|
||
The subclass object isn't deallocated until all deinitializers in its inheritance chain
|
||
have finished executing.
|
||
|
||
Deinitializers aren't called directly.
|
||
|
||
For an example of how to use a deinitializer in a class declaration,
|
||
see <doc:Deinitialization>.
|
||
|
||
> Grammar of a deinitializer declaration:
|
||
>
|
||
> *deinitializer-declaration* → *attributes*_?_ **`deinit`** *code-block*
|
||
|
||
## Extension Declaration
|
||
|
||
An *extension declaration* allows you to extend
|
||
the behavior of existing types.
|
||
Extension declarations are declared using the `extension` keyword
|
||
and have the following form:
|
||
|
||
```swift
|
||
extension <#type name#> where <#requirements#> {
|
||
<#declarations#>
|
||
}
|
||
```
|
||
|
||
The body of an extension declaration contains zero or more *declarations*.
|
||
These *declarations* can include computed properties, computed type properties,
|
||
instance methods, type methods, initializers, subscript declarations,
|
||
and even class, structure, and enumeration declarations.
|
||
Extension declarations can't contain deinitializer or protocol declarations,
|
||
stored properties, property observers, or other extension declarations.
|
||
Declarations in a protocol extension can't be marked `final`.
|
||
For a discussion and several examples of extensions that include various kinds of declarations,
|
||
see <doc:Extensions>.
|
||
|
||
If the *type name* is a class, structure, or enumeration type,
|
||
the extension extends that type.
|
||
If the *type name* is a protocol type,
|
||
the extension extends all types that conform to that protocol.
|
||
|
||
Extension declarations that extend a generic type
|
||
or a protocol with associated types
|
||
can include *requirements*.
|
||
If an instance of the extended type
|
||
or of a type that conforms to the extended protocol
|
||
satisfies the *requirements*,
|
||
the instance gains the behavior specified in the declaration.
|
||
|
||
Extension declarations can contain initializer declarations. That said,
|
||
if the type you're extending is defined in another module,
|
||
an initializer declaration must delegate to an initializer already defined in that module
|
||
to ensure members of that type are properly initialized.
|
||
|
||
Properties, methods, and initializers of an existing type
|
||
can't be overridden in an extension of that type.
|
||
|
||
Extension declarations can add protocol conformance to an existing
|
||
class, structure, or enumeration type by specifying *adopted protocols*:
|
||
|
||
```swift
|
||
extension <#type name#>: <#adopted protocols#> where <#requirements#> {
|
||
<#declarations#>
|
||
}
|
||
```
|
||
|
||
Extension declarations can't add class inheritance to an existing class,
|
||
and therefore you can specify only a list of protocols after the *type name* and colon.
|
||
|
||
### Conditional Conformance
|
||
|
||
You can extend a generic type
|
||
to conditionally conform to a protocol,
|
||
so that instances of the type conform to the protocol
|
||
only when certain requirements are met.
|
||
You add conditional conformance to a protocol
|
||
by including *requirements* in an extension declaration.
|
||
|
||
#### Overridden Requirements Aren't Used in Some Generic Contexts
|
||
|
||
In some generic contexts,
|
||
types that get behavior from conditional conformance to a protocol
|
||
don't always use the specialized implementations
|
||
of that protocol's requirements.
|
||
To illustrate this behavior,
|
||
the following example defines two protocols
|
||
and a generic type that conditionally conforms to both protocols.
|
||
|
||
<!--
|
||
This test needs to be compiled so that it will recognize Pair's
|
||
CustomStringConvertible conformance -- the deprecated REPL doesn't
|
||
seem to use the description property at all.
|
||
-->
|
||
|
||
```swift
|
||
protocol Loggable {
|
||
func log()
|
||
}
|
||
extension Loggable {
|
||
func log() {
|
||
print(self)
|
||
}
|
||
}
|
||
|
||
protocol TitledLoggable: Loggable {
|
||
static var logTitle: String { get }
|
||
}
|
||
extension TitledLoggable {
|
||
func log() {
|
||
print("\(Self.logTitle): \(self)")
|
||
}
|
||
}
|
||
|
||
struct Pair<T>: CustomStringConvertible {
|
||
let first: T
|
||
let second: T
|
||
var description: String {
|
||
return "(\(first), \(second))"
|
||
}
|
||
}
|
||
|
||
extension Pair: Loggable where T: Loggable { }
|
||
extension Pair: TitledLoggable where T: TitledLoggable {
|
||
static var logTitle: String {
|
||
return "Pair of '\(T.logTitle)'"
|
||
}
|
||
}
|
||
|
||
extension String: TitledLoggable {
|
||
static var logTitle: String {
|
||
return "String"
|
||
}
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `conditional-conformance`
|
||
|
||
```swifttest
|
||
-> protocol Loggable {
|
||
func log()
|
||
}
|
||
extension Loggable {
|
||
func log() {
|
||
print(self)
|
||
}
|
||
}
|
||
|
||
protocol TitledLoggable: Loggable {
|
||
static var logTitle: String { get }
|
||
}
|
||
extension TitledLoggable {
|
||
func log() {
|
||
print("\(Self.logTitle): \(self)")
|
||
}
|
||
}
|
||
|
||
struct Pair<T>: CustomStringConvertible {
|
||
let first: T
|
||
let second: T
|
||
var description: String {
|
||
return "(\(first), \(second))"
|
||
}
|
||
}
|
||
|
||
extension Pair: Loggable where T: Loggable { }
|
||
extension Pair: TitledLoggable where T: TitledLoggable {
|
||
static var logTitle: String {
|
||
return "Pair of '\(T.logTitle)'"
|
||
}
|
||
}
|
||
|
||
extension String: TitledLoggable {
|
||
static var logTitle: String {
|
||
return "String"
|
||
}
|
||
}
|
||
```
|
||
-->
|
||
|
||
The `Pair` structure conforms to `Loggable` and `TitledLoggable`
|
||
whenever its generic type conforms to `Loggable` or `TitledLoggable`, respectively.
|
||
In the example below,
|
||
`oneAndTwo` is an instance of `Pair<String>`,
|
||
which conforms to `TitledLoggable`
|
||
because `String` conforms to `TitledLoggable`.
|
||
When the `log()` method is called on `oneAndTwo` directly,
|
||
the specialized version containing the title string is used.
|
||
|
||
```swift
|
||
let oneAndTwo = Pair(first: "one", second: "two")
|
||
oneAndTwo.log()
|
||
// Prints "Pair of 'String': (one, two)".
|
||
```
|
||
|
||
<!--
|
||
- test: `conditional-conformance`
|
||
|
||
```swifttest
|
||
-> let oneAndTwo = Pair(first: "one", second: "two")
|
||
-> oneAndTwo.log()
|
||
<- Pair of 'String': (one, two)
|
||
```
|
||
-->
|
||
|
||
However, when `oneAndTwo` is used in a generic context
|
||
or as an instance of the `Loggable` protocol,
|
||
the specialized version isn't used.
|
||
Swift picks which implementation of `log()` to call
|
||
by consulting only the minimum requirements that `Pair` needs to conform to `Loggable`.
|
||
For this reason,
|
||
the default implementation provided by the `Loggable` protocol is used instead.
|
||
|
||
```swift
|
||
func doSomething<T: Loggable>(with x: T) {
|
||
x.log()
|
||
}
|
||
doSomething(with: oneAndTwo)
|
||
// Prints "(one, two)".
|
||
```
|
||
|
||
<!--
|
||
- test: `conditional-conformance`
|
||
|
||
```swifttest
|
||
-> func doSomething<T: Loggable>(with x: T) {
|
||
x.log()
|
||
}
|
||
doSomething(with: oneAndTwo)
|
||
<- (one, two)
|
||
```
|
||
-->
|
||
|
||
When `log()` is called on the instance that's passed to `doSomething(_:)`,
|
||
the customized title is omitted from the logged string.
|
||
|
||
### Protocol Conformance Must Not Be Redundant
|
||
|
||
A concrete type can conform to a particular protocol only once.
|
||
Swift marks redundant protocol conformances as an error.
|
||
You're likely to encounter this kind of error
|
||
in two kinds of situations.
|
||
The first situation is when
|
||
you explicitly conform to the same protocol multiple times,
|
||
but with different requirements.
|
||
The second situation is when
|
||
you implicitly inherit from the same protocol multiple times.
|
||
These situations are discussed in the sections below.
|
||
|
||
#### Resolving Explicit Redundancy
|
||
|
||
Multiple extensions on a concrete type
|
||
can't add conformance to the same protocol,
|
||
even if the extensions' requirements are mutually exclusive.
|
||
This restriction is demonstrated in the example below.
|
||
Two extension declarations attempt to add conditional conformance
|
||
to the `Serializable` protocol,
|
||
one for arrays with `Int` elements,
|
||
and one for arrays with `String` elements.
|
||
|
||
```swift
|
||
protocol Serializable {
|
||
func serialize() -> Any
|
||
}
|
||
|
||
extension Array: Serializable where Element == Int {
|
||
func serialize() -> Any {
|
||
// implementation
|
||
}
|
||
}
|
||
extension Array: Serializable where Element == String {
|
||
func serialize() -> Any {
|
||
// implementation
|
||
}
|
||
}
|
||
// Error: Redundant conformance of 'Array<Element>' to protocol 'Serializable'.
|
||
```
|
||
|
||
<!--
|
||
- test: `multiple-conformances`
|
||
|
||
```swifttest
|
||
-> protocol Serializable {
|
||
func serialize() -> Any
|
||
}
|
||
|
||
extension Array: Serializable where Element == Int {
|
||
func serialize() -> Any {
|
||
// implementation
|
||
>> return 0
|
||
-> }
|
||
}
|
||
extension Array: Serializable where Element == String {
|
||
func serialize() -> Any {
|
||
// implementation
|
||
>> return 0
|
||
-> }
|
||
}
|
||
// Error: Redundant conformance of 'Array<Element>' to protocol 'Serializable'.
|
||
!$ error: conflicting conformance of 'Array<Element>' to protocol 'Serializable'; there cannot be more than one conformance, even with different conditional bounds
|
||
!! extension Array: Serializable where Element == String {
|
||
!! ^
|
||
!$ note: 'Array<Element>' declares conformance to protocol 'Serializable' here
|
||
!! extension Array: Serializable where Element == Int {
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
If you need to add conditional conformance based on multiple concrete types,
|
||
create a new protocol that each type can conform to
|
||
and use that protocol as the requirement when declaring conditional conformance.
|
||
|
||
```swift
|
||
protocol SerializableInArray { }
|
||
extension Int: SerializableInArray { }
|
||
extension String: SerializableInArray { }
|
||
|
||
extension Array: Serializable where Element: SerializableInArray {
|
||
func serialize() -> Any {
|
||
// implementation
|
||
}
|
||
}
|
||
```
|
||
|
||
<!--
|
||
- test: `multiple-conformances-success`
|
||
|
||
```swifttest
|
||
>> protocol Serializable { }
|
||
-> protocol SerializableInArray { }
|
||
extension Int: SerializableInArray { }
|
||
extension String: SerializableInArray { }
|
||
|
||
-> extension Array: Serializable where Element: SerializableInArray {
|
||
func serialize() -> Any {
|
||
// implementation
|
||
>> return 0
|
||
-> }
|
||
}
|
||
```
|
||
-->
|
||
|
||
#### Resolving Implicit Redundancy
|
||
|
||
When a concrete type conditionally conforms to a protocol,
|
||
that type implicitly conforms to any parent protocols
|
||
with the same requirements.
|
||
|
||
If you need a type to conditionally conform to two protocols
|
||
that inherit from a single parent,
|
||
explicitly declare conformance to the parent protocol.
|
||
This avoids implicitly conforming to the parent protocol twice
|
||
with different requirements.
|
||
|
||
The following example explicitly declares
|
||
the conditional conformance of `Array` to `Loggable`
|
||
to avoid a conflict when declaring its conditional conformance
|
||
to both `TitledLoggable` and the new `MarkedLoggable` protocol.
|
||
|
||
```swift
|
||
protocol MarkedLoggable: Loggable {
|
||
func markAndLog()
|
||
}
|
||
|
||
extension MarkedLoggable {
|
||
func markAndLog() {
|
||
print("----------")
|
||
log()
|
||
}
|
||
}
|
||
|
||
extension Array: Loggable where Element: Loggable { }
|
||
extension Array: TitledLoggable where Element: TitledLoggable {
|
||
static var logTitle: String {
|
||
return "Array of '\(Element.logTitle)'"
|
||
}
|
||
}
|
||
extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
```
|
||
|
||
<!--
|
||
- test: `conditional-conformance`
|
||
|
||
```swifttest
|
||
-> protocol MarkedLoggable: Loggable {
|
||
func markAndLog()
|
||
}
|
||
|
||
extension MarkedLoggable {
|
||
func markAndLog() {
|
||
print("----------")
|
||
log()
|
||
}
|
||
}
|
||
|
||
extension Array: Loggable where Element: Loggable { }
|
||
extension Array: TitledLoggable where Element: TitledLoggable {
|
||
static var logTitle: String {
|
||
return "Array of '\(Element.logTitle)'"
|
||
}
|
||
}
|
||
extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
```
|
||
-->
|
||
|
||
Without the extension
|
||
to explicitly declare conditional conformance to `Loggable`,
|
||
the other `Array` extensions would implicitly create these declarations,
|
||
resulting in an error:
|
||
|
||
```swift
|
||
extension Array: Loggable where Element: TitledLoggable { }
|
||
extension Array: Loggable where Element: MarkedLoggable { }
|
||
// Error: Redundant conformance of 'Array<Element>' to protocol 'Loggable'.
|
||
```
|
||
|
||
<!--
|
||
- test: `conditional-conformance-implicit-overlap`
|
||
|
||
```swifttest
|
||
>> protocol Loggable { }
|
||
>> protocol MarkedLoggable : Loggable { }
|
||
>> protocol TitledLoggable : Loggable { }
|
||
-> extension Array: Loggable where Element: TitledLoggable { }
|
||
extension Array: Loggable where Element: MarkedLoggable { }
|
||
// Error: Redundant conformance of 'Array<Element>' to protocol 'Loggable'.
|
||
!$ error: conflicting conformance of 'Array<Element>' to protocol 'Loggable'; there cannot be more than one conformance, even with different conditional bounds
|
||
!! extension Array: Loggable where Element: MarkedLoggable { }
|
||
!! ^
|
||
!$ note: 'Array<Element>' declares conformance to protocol 'Loggable' here
|
||
!! extension Array: Loggable where Element: TitledLoggable { }
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
- test: `types-cant-have-multiple-implicit-conformances`
|
||
|
||
```swifttest
|
||
>> protocol Loggable { }
|
||
protocol TitledLoggable: Loggable { }
|
||
protocol MarkedLoggable: Loggable { }
|
||
extension Array: TitledLoggable where Element: TitledLoggable {
|
||
// ...
|
||
}
|
||
extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
!$ error: conditional conformance of type 'Array<Element>' to protocol 'TitledLoggable' does not imply conformance to inherited protocol 'Loggable'
|
||
!! extension Array: TitledLoggable where Element: TitledLoggable {
|
||
!! ^
|
||
!$ note: did you mean to explicitly state the conformance like 'extension Array: Loggable where ...'?
|
||
!! extension Array: TitledLoggable where Element: TitledLoggable {
|
||
!! ^
|
||
!$ error: type 'Array<Element>' does not conform to protocol 'MarkedLoggable'
|
||
!! extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
!! ^
|
||
!$ error: type 'Element' does not conform to protocol 'TitledLoggable'
|
||
!! extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
!! ^
|
||
!$ error: 'MarkedLoggable' requires that 'Element' conform to 'TitledLoggable'
|
||
!! extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
!! ^
|
||
!$ note: requirement specified as 'Element' : 'TitledLoggable'
|
||
!! extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
!! ^
|
||
!$ note: requirement from conditional conformance of 'Array<Element>' to 'Loggable'
|
||
!! extension Array: MarkedLoggable where Element: MarkedLoggable { }
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
- test: `extension-can-have-where-clause`
|
||
|
||
```swifttest
|
||
>> extension Array where Element: Equatable {
|
||
func f(x: Array) -> Int { return 7 }
|
||
}
|
||
>> let x = [1, 2, 3]
|
||
>> let y = [10, 20, 30]
|
||
>> let r0 = x.f(x: y)
|
||
>> assert(r0 == 7)
|
||
```
|
||
-->
|
||
|
||
<!--
|
||
- test: `extensions-can-have-where-clause-and-inheritance-together`
|
||
|
||
```swifttest
|
||
>> protocol P { func foo() -> Int }
|
||
>> extension Array: P where Element: Equatable {
|
||
>> func foo() -> Int { return 0 }
|
||
>> }
|
||
>> let r0 = [1, 2, 3].foo()
|
||
>> assert(r0 == 0)
|
||
```
|
||
-->
|
||
|
||
> Grammar of an extension declaration:
|
||
>
|
||
> *extension-declaration* → *attributes*_?_ *access-level-modifier*_?_ **`extension`** *type-identifier* *type-inheritance-clause*_?_ *generic-where-clause*_?_ *extension-body* \
|
||
> *extension-body* → **`{`** *extension-members*_?_ **`}`**
|
||
>
|
||
> *extension-members* → *extension-member* *extension-members*_?_ \
|
||
> *extension-member* → *declaration* | *compiler-control-statement*
|
||
|
||
## Subscript Declaration
|
||
|
||
A *subscript* declaration allows you to add subscripting support for objects
|
||
of a particular type and are typically used to provide a convenient syntax
|
||
for accessing the elements in a collection, list, or sequence.
|
||
Subscript declarations are declared using the `subscript` keyword
|
||
and have the following form:
|
||
|
||
```swift
|
||
subscript (<#parameters#>) -> <#return type#> {
|
||
get {
|
||
<#statements#>
|
||
}
|
||
set(<#setter name#>) {
|
||
<#statements#>
|
||
}
|
||
}
|
||
```
|
||
|
||
Subscript declarations can appear only in the context of a class, structure,
|
||
enumeration, extension, or protocol declaration.
|
||
|
||
The *parameters* specify one or more indexes used to access elements of the corresponding type
|
||
in a subscript expression (for example, the `i` in the expression `object[i]`).
|
||
Although the indexes used to access the elements can be of any type,
|
||
each parameter must include a type annotation to specify the type of each index.
|
||
The *return type* specifies the type of the element being accessed.
|
||
|
||
As with computed properties,
|
||
subscript declarations support reading and writing the value of the accessed elements.
|
||
The getter is used to read the value,
|
||
and the setter is used to write the value.
|
||
The setter clause is optional,
|
||
and when only a getter is needed, you can omit both clauses and simply
|
||
return the requested value directly.
|
||
That said, if you provide a setter clause, you must also provide a getter clause.
|
||
|
||
The *setter name* and enclosing parentheses are optional.
|
||
If you provide a setter name, it's used as the name of the parameter to the setter.
|
||
If you don't provide a setter name, the default parameter name to the setter is `newValue`.
|
||
The type of the parameter to the setter is the same as the *return type*.
|
||
|
||
You can overload a subscript declaration in the type in which it's declared,
|
||
as long as the *parameters* or the *return type* differ from the one you're overloading.
|
||
You can also override a subscript declaration inherited from a superclass. When you do so,
|
||
you must mark the overridden subscript declaration with the `override` declaration modifier.
|
||
|
||
Subscript parameters follow the same rules as function parameters,
|
||
with two exceptions.
|
||
By default, the parameters used in subscripting don't have argument labels,
|
||
unlike functions, methods, and initializers.
|
||
However, you can provide explicit argument labels
|
||
using the same syntax that functions, methods, and initializers use.
|
||
In addition, subscripts can't have in-out parameters.
|
||
A subscript parameter can have a default value,
|
||
using the syntax described in <doc:Declarations#Special-Kinds-of-Parameters>.
|
||
|
||
You can also declare subscripts in the context of a protocol declaration,
|
||
as described in <doc:Declarations#Protocol-Subscript-Declaration>.
|
||
|
||
For more information about subscripting and to see examples of subscript declarations,
|
||
see <doc:Subscripts>.
|
||
|
||
### Type Subscript Declarations
|
||
|
||
To declare a subscript that's exposed by the type,
|
||
rather than by instances of the type,
|
||
mark the subscript declaration with the `static` declaration modifier.
|
||
Classes can mark type computed properties with the `class` declaration modifier instead
|
||
to allow subclasses to override the superclass’s implementation.
|
||
In a class declaration,
|
||
the `static` keyword has the same effect as marking the declaration
|
||
with both the `class` and `final` declaration modifiers.
|
||
|
||
<!--
|
||
- test: `cant-override-static-subscript-in-subclass`
|
||
|
||
```swifttest
|
||
-> class Super { static subscript(i: Int) -> Int { return 10 } }
|
||
-> class Sub: Super { override static subscript(i: Int) -> Int { return 100 } }
|
||
!$ error: cannot override static subscript
|
||
!! class Sub: Super { override static subscript(i: Int) -> Int { return 100 } }
|
||
!! ^
|
||
!$ note: overridden declaration is here
|
||
!! class Super { static subscript(i: Int) -> Int { return 10 } }
|
||
!! ^
|
||
```
|
||
-->
|
||
|
||
> Grammar of a subscript declaration:
|
||
>
|
||
> *subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause*_?_ *code-block* \
|
||
> *subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause*_?_ *getter-setter-block* \
|
||
> *subscript-declaration* → *subscript-head* *subscript-result* *generic-where-clause*_?_ *getter-setter-keyword-block* \
|
||
> *subscript-head* → *attributes*_?_ *declaration-modifiers*_?_ **`subscript`** *generic-parameter-clause*_?_ *parameter-clause* \
|
||
> *subscript-result* → **`->`** *attributes*_?_ *type*
|
||
|
||
## Macro Declaration
|
||
|
||
A *macro declaration* introduces a new macro.
|
||
It begins with the `macro` keyword
|
||
and has the following form:
|
||
|
||
```swift
|
||
macro <#name#> = <#macro implementation#>
|
||
```
|
||
|
||
The *macro implementation* is another macro,
|
||
and indicates the location of the code that performs this macro's expansion.
|
||
The code that performs macro expansion is a separate Swift program,
|
||
that uses the [SwiftSyntax][] module to interact with Swift code.
|
||
Call the `externalMacro(module:type:)` macro from the Swift standard library,
|
||
passing in the name of a type that contains the macro's implementation,
|
||
and the name of the module that contains that type.
|
||
|
||
[SwiftSyntax]: https://github.com/swiftlang/swift-syntax
|
||
|
||
Macros can be overloaded,
|
||
following the same model used by functions.
|
||
A macro declaration appears only at file scope.
|
||
|
||
For an overview of macros in Swift, see <doc:Macros>.
|
||
|
||
> Grammar of a macro declaration:
|
||
>
|
||
> *macro-declaration* → *macro-head* *identifier* *generic-parameter-clause*_?_ *macro-signature* *macro-definition*_?_ *generic-where-clause* \
|
||
> *macro-head* → *attributes*_?_ *declaration-modifiers*_?_ **`macro`** \
|
||
> *macro-signature* → *parameter-clause* *macro-function-signature-result*_?_ \
|
||
> *macro-function-signature-result* → **`->`** *type* \
|
||
> *macro-definition* → **`=`** *expression*
|
||
|
||
## Operator Declaration
|
||
|
||
An *operator declaration* introduces a new infix, prefix,
|
||
or postfix operator into your program
|
||
and is declared using the `operator` keyword.
|
||
|
||
You can declare operators of three different fixities:
|
||
infix, prefix, and postfix.
|
||
The *fixity* of an operator specifies the relative position of an operator
|
||
to its operands.
|
||
|
||
There are three basic forms of an operator declaration,
|
||
one for each fixity.
|
||
The fixity of the operator is specified by marking the operator declaration with the
|
||
`infix`, `prefix`, or `postfix` declaration modifier before the `operator` keyword.
|
||
In each form, the name of the operator can contain only the operator characters
|
||
defined in <doc:LexicalStructure#Operators>.
|
||
|
||
The following form declares a new infix operator:
|
||
|
||
```swift
|
||
infix operator <#operator name#>: <#precedence group#>
|
||
```
|
||
|
||
An *infix operator* is a binary operator that's written between its two operands,
|
||
such as the familiar addition operator (`+`) in the expression `1 + 2`.
|
||
|
||
Infix operators can optionally specify a precedence group.
|
||
If you omit the precedence group for an operator,
|
||
Swift uses the default precedence group, `DefaultPrecedence`,
|
||
which specifies a precedence just higher than `TernaryPrecedence`.
|
||
For more information, see <doc:Declarations#Precedence-Group-Declaration>.
|
||
|
||
The following form declares a new prefix operator:
|
||
|
||
```swift
|
||
prefix operator <#operator name#>
|
||
```
|
||
|
||
A *prefix operator* is a unary operator that's written immediately before its operand,
|
||
such as the prefix logical NOT operator (`!`) in the expression `!a`.
|
||
|
||
Prefix operators declarations don't specify a precedence level.
|
||
Prefix operators are nonassociative.
|
||
|
||
The following form declares a new postfix operator:
|
||
|
||
```swift
|
||
postfix operator <#operator name#>
|
||
```
|
||
|
||
A *postfix operator* is a unary operator that's written immediately after its operand,
|
||
such as the postfix forced-unwrap operator (`!`) in the expression `a!`.
|
||
|
||
As with prefix operators, postfix operator declarations don't specify a precedence level.
|
||
Postfix operators are nonassociative.
|
||
|
||
After declaring a new operator,
|
||
you implement it by declaring a static method that has the same name as the operator.
|
||
The static method is a member of
|
||
one of the types whose values the operator takes as an argument ---
|
||
for example, an operator that multiplies a `Double` by an `Int`
|
||
is implemented as a static method on either the `Double` or `Int` structure.
|
||
If you're implementing a prefix or postfix operator,
|
||
you must also mark that method declaration with the corresponding `prefix` or `postfix`
|
||
declaration modifier.
|
||
To see an example of how to create and implement a new operator,
|
||
see <doc:AdvancedOperators#Custom-Operators>.
|
||
|
||
> Grammar of an operator declaration:
|
||
>
|
||
> *operator-declaration* → *prefix-operator-declaration* | *postfix-operator-declaration* | *infix-operator-declaration*
|
||
>
|
||
> *prefix-operator-declaration* → **`prefix`** **`operator`** *operator* \
|
||
> *postfix-operator-declaration* → **`postfix`** **`operator`** *operator* \
|
||
> *infix-operator-declaration* → **`infix`** **`operator`** *operator* *infix-operator-group*_?_
|
||
>
|
||
> *infix-operator-group* → **`:`** *precedence-group-name*
|
||
|
||
## Precedence Group Declaration
|
||
|
||
A *precedence group declaration* introduces
|
||
a new grouping for infix operator precedence into your program.
|
||
The precedence of an operator specifies how tightly the operator
|
||
binds to its operands, in the absence of grouping parentheses.
|
||
|
||
A precedence group declaration has the following form:
|
||
|
||
```swift
|
||
precedencegroup <#precedence group name#> {
|
||
higherThan: <#lower group names#>
|
||
lowerThan: <#higher group names#>
|
||
associativity: <#associativity#>
|
||
assignment: <#assignment#>
|
||
}
|
||
```
|
||
|
||
The *lower group names* and *higher group names* lists specify
|
||
the new precedence group's relation to existing precedence groups.
|
||
The `lowerThan` precedence group attribute may only be used
|
||
to refer to precedence groups declared outside of the current module.
|
||
When two operators compete with each other for their operands,
|
||
such as in the expression `2 + 3 * 5`,
|
||
the operator with the higher relative precedence
|
||
binds more tightly to its operands.
|
||
|
||
> Note: Precedence groups related to each other
|
||
> using *lower group names* and *higher group names*
|
||
> must fit into a single relational hierarchy,
|
||
> but they *don't* have to form a linear hierarchy.
|
||
> This means it's possible to have precedence groups
|
||
> with undefined relative precedence.
|
||
> Operators from those precedence groups
|
||
> can't be used next to each other without grouping parentheses.
|
||
|
||
Swift defines numerous precedence groups to go along
|
||
with the operators provided by the Swift standard library.
|
||
For example, the addition (`+`) and subtraction (`-`) operators
|
||
belong to the `AdditionPrecedence` group,
|
||
and the multiplication (`*`) and division (`/`) operators
|
||
belong to the `MultiplicationPrecedence` group.
|
||
For a complete list of precedence groups
|
||
provided by the Swift standard library,
|
||
see [Operator Declarations](https://developer.apple.com/documentation/swift/operator_declarations).
|
||
|
||
The *associativity* of an operator specifies how a sequence of operators
|
||
with the same precedence level are grouped together in the absence of grouping parentheses.
|
||
You specify the associativity of an operator by writing
|
||
one of the context-sensitive keywords `left`, `right`, or `none` ---
|
||
if your omit the associativity, the default is `none`.
|
||
Operators that are left-associative group left-to-right.
|
||
For example,
|
||
the subtraction operator (`-`) is left-associative,
|
||
so the expression `4 - 5 - 6` is grouped as `(4 - 5) - 6`
|
||
and evaluates to `-7`.
|
||
Operators that are right-associative group right-to-left,
|
||
and operators that are specified with an associativity of `none`
|
||
don't associate at all.
|
||
Nonassociative operators of the same precedence level
|
||
can't appear adjacent to each to other.
|
||
For example,
|
||
the `<` operator has an associativity of `none`,
|
||
which means `1 < 2 < 3` isn't a valid expression.
|
||
|
||
The *assignment* of a precedence group specifies the precedence of an operator
|
||
when used in an operation that includes optional chaining.
|
||
When set to `true`, an operator in the corresponding precedence group
|
||
uses the same grouping rules during optional chaining
|
||
as the assignment operators from the Swift standard library.
|
||
Otherwise, when set to `false` or omitted,
|
||
operators in the precedence group follows the same optional chaining rules
|
||
as operators that don't perform assignment.
|
||
|
||
> Grammar of a precedence group declaration:
|
||
>
|
||
> *precedence-group-declaration* → **`precedencegroup`** *precedence-group-name* **`{`** *precedence-group-attributes*_?_ **`}`**
|
||
>
|
||
> *precedence-group-attributes* → *precedence-group-attribute* *precedence-group-attributes*_?_ \
|
||
> *precedence-group-attribute* → *precedence-group-relation* \
|
||
> *precedence-group-attribute* → *precedence-group-assignment* \
|
||
> *precedence-group-attribute* → *precedence-group-associativity*
|
||
>
|
||
> *precedence-group-relation* → **`higherThan`** **`:`** *precedence-group-names* \
|
||
> *precedence-group-relation* → **`lowerThan`** **`:`** *precedence-group-names*
|
||
>
|
||
> *precedence-group-assignment* → **`assignment`** **`:`** *boolean-literal*
|
||
>
|
||
> *precedence-group-associativity* → **`associativity`** **`:`** **`left`** \
|
||
> *precedence-group-associativity* → **`associativity`** **`:`** **`right`** \
|
||
> *precedence-group-associativity* → **`associativity`** **`:`** **`none`**
|
||
>
|
||
> *precedence-group-names* → *precedence-group-name* | *precedence-group-name* **`,`** *precedence-group-names* \
|
||
> *precedence-group-name* → *identifier*
|
||
|
||
## Declaration Modifiers
|
||
|
||
*Declaration modifiers* are keywords or context-sensitive keywords that modify the behavior
|
||
or meaning of a declaration. You specify a declaration modifier by writing the appropriate
|
||
keyword or context-sensitive keyword between a declaration's attributes (if any) and the keyword
|
||
that introduces the declaration.
|
||
|
||
- term `class`:
|
||
Apply this modifier to a member of a class
|
||
to indicate that the member is a member of the class itself,
|
||
rather than a member of instances of the class.
|
||
Members of a superclass that have this modifier
|
||
and don't have the `final` modifier
|
||
can be overridden by subclasses.
|
||
|
||
- term `dynamic`:
|
||
Apply this modifier to any member of a class that can be represented by Objective-C.
|
||
When you mark a member declaration with the `dynamic` modifier,
|
||
access to that member is always dynamically dispatched using the Objective-C runtime.
|
||
Access to that member is never inlined or devirtualized by the compiler.
|
||
|
||
Because declarations marked with the `dynamic` modifier are dispatched
|
||
using the Objective-C runtime, they must be marked with the
|
||
`objc` attribute.
|
||
|
||
- term `final`:
|
||
Apply this modifier to a class or to a property, method,
|
||
or subscript member of a class. It's applied to a class to indicate that the class
|
||
can't be subclassed. It's applied to a property, method, or subscript of a class
|
||
to indicate that a class member can't be overridden in any subclass.
|
||
For an example of how to use the `final` attribute,
|
||
see <doc:Inheritance#Preventing-Overrides>.
|
||
|
||
- term `lazy`:
|
||
Apply this modifier to a stored variable property of a class or structure
|
||
to indicate that the property's initial value is calculated and stored at most
|
||
once, when the property is first accessed.
|
||
For an example of how to use the `lazy` modifier,
|
||
see <doc:Properties#Lazy-Stored-Properties>.
|
||
|
||
- term `optional`:
|
||
Apply this modifier to a protocol's property, method,
|
||
or subscript members to indicate that a conforming type isn't required
|
||
to implement those members.
|
||
|
||
You can apply the `optional` modifier only to protocols that are marked
|
||
with the `objc` attribute. As a result, only class types can adopt and conform
|
||
to a protocol that contains optional member requirements.
|
||
For more information about how to use the `optional` modifier
|
||
and for guidance about how to access optional protocol members ---
|
||
for example, when you're not sure whether a conforming type implements them ---
|
||
see <doc:Protocols#Optional-Protocol-Requirements>.
|
||
|
||
<!--
|
||
TODO: Currently, you can't check for an optional initializer,
|
||
so we're leaving those out of the documentation, even though you can mark
|
||
an initializer with the @optional attribute. It's still being decided by the
|
||
compiler team. Update this section if they decide to make everything work
|
||
properly for optional initializer requirements.
|
||
-->
|
||
|
||
- term `required`:
|
||
Apply this modifier to a designated or convenience initializer
|
||
of a class to indicate that every subclass must implement that initializer.
|
||
The subclass's implementation of that initializer
|
||
must also be marked with the `required` modifier.
|
||
|
||
- term `static`:
|
||
Apply this modifier to a member of a structure, class, enumeration, or protocol
|
||
to indicate that the member is a member of the type,
|
||
rather than a member of instances of that type.
|
||
In the scope of a class declaration,
|
||
writing the `static` modifier on a member declaration
|
||
has the same effect as writing the `class` and `final` modifiers
|
||
on that member declaration.
|
||
However, constant type properties of a class are an exception:
|
||
`static` has its normal, nonclass meaning there
|
||
because you can't write `class` or `final` on those declarations.
|
||
|
||
- term `unowned`:
|
||
Apply this modifier to a stored variable, constant, or stored property
|
||
to indicate that the variable or property has an unowned reference
|
||
to the object stored as its value.
|
||
If you try to access the variable or property
|
||
after the object has been deallocated,
|
||
a runtime error is raised.
|
||
Like a weak reference,
|
||
the type of the property or value must be a class type;
|
||
unlike a weak reference,
|
||
the type is non-optional.
|
||
For an example and more information about the `unowned` modifier,
|
||
see <doc:AutomaticReferenceCounting#Unowned-References>.
|
||
|
||
- term `unowned(safe)`:
|
||
An explicit spelling of `unowned`.
|
||
|
||
- term `unowned(unsafe)`:
|
||
Apply this modifier to a stored variable, constant, or stored property
|
||
to indicate that the variable or property has an unowned reference
|
||
to the object stored as its value.
|
||
If you try to access the variable or property
|
||
after the object has been deallocated,
|
||
you'll access the memory at the location where the object used to be,
|
||
which is a memory-unsafe operation.
|
||
Like a weak reference,
|
||
the type of the property or value must be a class type;
|
||
unlike a weak reference,
|
||
the type is non-optional.
|
||
For an example and more information about the `unowned` modifier,
|
||
see <doc:AutomaticReferenceCounting#Unowned-References>.
|
||
|
||
- term `weak`:
|
||
Apply this modifier to a stored variable or stored variable property
|
||
to indicate that the variable or property has a weak reference to the
|
||
object stored as its value. The type of the variable or property
|
||
must be an optional class type.
|
||
If you access the variable or property
|
||
after the object has been deallocated,
|
||
its value is `nil`.
|
||
For an example and more information about the `weak` modifier,
|
||
see <doc:AutomaticReferenceCounting#Weak-References>.
|
||
|
||
### Access Control Levels
|
||
|
||
Swift provides five levels of access control: open, public, internal, file private, and private.
|
||
You can mark a declaration with one of the access-level modifiers below
|
||
to specify the declaration's access level.
|
||
Access control is discussed in detail in <doc:AccessControl>.
|
||
|
||
- term `open`:
|
||
Apply this modifier to a declaration to indicate the declaration can be accessed and subclassed
|
||
by code in the same module as the declaration.
|
||
Declarations marked with the `open` access-level modifier can also be accessed and subclassed
|
||
by code in a module that imports the module that contains that declaration.
|
||
|
||
- term `public`:
|
||
Apply this modifier to a declaration to indicate the declaration can be accessed and subclassed
|
||
by code in the same module as the declaration.
|
||
Declarations marked with the `public` access-level modifier can also be accessed (but not subclassed)
|
||
by code in a module that imports the module that contains that declaration.
|
||
|
||
- term `package`:
|
||
Apply this modifier to a declaration
|
||
to indicate that the declaration can be accessed
|
||
only by code in the same package as the declaration.
|
||
A package is a unit of code distribution
|
||
that you define in the build system you're using.
|
||
When the build system compiles code,
|
||
it specifies the package name
|
||
by passing the `-package-name` flag to the Swift compiler.
|
||
Two modules are part of the same package
|
||
if the build system specifies the same package name when building them.
|
||
|
||
- term `internal`:
|
||
Apply this modifier to a declaration to indicate the declaration can be accessed
|
||
only by code in the same module as the declaration.
|
||
By default,
|
||
most declarations are implicitly marked with the `internal` access-level modifier.
|
||
|
||
- term `fileprivate`:
|
||
Apply this modifier to a declaration to indicate the declaration can be accessed
|
||
only by code in the same source file as the declaration.
|
||
|
||
- term `private`:
|
||
Apply this modifier to a declaration to indicate the declaration can be accessed
|
||
only by code within the declaration's immediate enclosing scope.
|
||
|
||
For the purpose of access control,
|
||
extensions behave as follows:
|
||
|
||
- If there are multiple extensions in the same file,
|
||
and those extensions all extend the same type,
|
||
then all of those extensions have the same access-control scope.
|
||
The extensions and the type they extend can be in different files.
|
||
|
||
- If there are extensions in the same file as the type they extend,
|
||
the extensions have the same access-control scope as the type they extend.
|
||
|
||
- Private members declared in a type's declaration
|
||
can be accessed from extensions to that type.
|
||
Private members declared in one extension
|
||
can be accessed from other extensions
|
||
and from the extended type's declaration.
|
||
|
||
Each access-level modifier above optionally accepts a single argument,
|
||
which consists of the `set` keyword enclosed in parentheses ---
|
||
for example, `private(set)`.
|
||
Use this form of an access-level modifier when you want to specify an access level
|
||
for the setter of a variable or subscript that's less than or equal
|
||
to the access level of the variable or subscript itself,
|
||
as discussed in <doc:AccessControl#Getters-and-Setters>.
|
||
|
||
> Grammar of a declaration modifier:
|
||
>
|
||
> *declaration-modifier* → **`class`** | **`convenience`** | **`dynamic`** | **`final`** | **`infix`** | **`lazy`** | **`optional`** | **`override`** | **`postfix`** | **`prefix`** | **`required`** | **`static`** | **`unowned`** | **`unowned`** **`(`** **`safe`** **`)`** | **`unowned`** **`(`** **`unsafe`** **`)`** | **`weak`** \
|
||
> *declaration-modifier* → *access-level-modifier* \
|
||
> *declaration-modifier* → *mutation-modifier* \
|
||
> *declaration-modifier* → *actor-isolation-modifier* \
|
||
> *declaration-modifiers* → *declaration-modifier* *declaration-modifiers*_?_
|
||
>
|
||
> *access-level-modifier* → **`private`** | **`private`** **`(`** **`set`** **`)`** \
|
||
> *access-level-modifier* → **`fileprivate`** | **`fileprivate`** **`(`** **`set`** **`)`** \
|
||
> *access-level-modifier* → **`internal`** | **`internal`** **`(`** **`set`** **`)`** \
|
||
> *access-level-modifier* → **`package`** | **`package`** **`(`** **`set`** **`)`** \
|
||
> *access-level-modifier* → **`public`** | **`public`** **`(`** **`set`** **`)`** \
|
||
> *access-level-modifier* → **`open`** | **`open`** **`(`** **`set`** **`)`**
|
||
>
|
||
> *mutation-modifier* → **`mutating`** | **`nonmutating`**
|
||
>
|
||
> *actor-isolation-modifier* → **`nonisolated`**
|
||
|
||
<!--
|
||
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
|
||
-->
|