Expressions
Access, modify, and assign values.
In Swift, there are four kinds of expressions: prefix expressions, infix expressions, primary expressions, and postfix expressions. Evaluating an expression returns a value, causes a side effect, or both.
Prefix and infix expressions let you apply operators to smaller expressions. Primary expressions are conceptually the simplest kind of expression, and they provide a way to access values. Postfix expressions, like prefix and infix expressions, let you build up more complex expressions using postfixes such as function calls and member access. Each kind of expression is described in detail in the sections below.
Grammar of an expression:
expression → try-operator? await-operator? prefix-expression infix-expressions?
Prefix Expressions
Prefix expressions combine an optional prefix operator with an expression. Prefix operators take one argument, the expression that follows them.
For information about the behavior of these operators, see doc:BasicOperators and doc:AdvancedOperators.
For information about the operators provided by the Swift standard library, see Operator Declarations.
Grammar of a prefix expression:
prefix-expression → prefix-operator? postfix-expression
prefix-expression → in-out-expression
In-Out Expression
An in-out expression marks a variable that's being passed as an in-out argument to a function call expression.
&<#expression#>
For more information about in-out parameters and to see an example, see doc:Functions#In-Out-Parameters.
In-out expressions are also used when providing a non-pointer argument in a context where a pointer is needed, as described in doc:Expressions#Implicit-Conversion-to-a-Pointer-Type.
Grammar of an in-out expression:
in-out-expression →
&primary-expression
Try Operator
A try expression consists of the try operator
followed by an expression that can throw an error.
It has the following form:
try <#expression#>
The value of a try expression is the value of the expression.
An optional-try expression consists of the try? operator
followed by an expression that can throw an error.
It has the following form:
try? <#expression#>
If the expression doesn't throw an error,
the value of the optional-try expression
is an optional containing the value of the expression.
Otherwise, the value of the optional-try expression is nil.
A forced-try expression consists of the try! operator
followed by an expression that can throw an error.
It has the following form:
try! <#expression#>
The value of a forced-try expression is the value of the expression. If the expression throws an error, a runtime error is produced.
When the expression on the left-hand side of an infix operator
is marked with try, try?, or try!,
that operator applies to the whole infix expression.
That said, you can use parentheses to be explicit about the scope of the operator's application.
// Writing 'try' applies to both function calls.
sum = try someThrowingFunction() + anotherThrowingFunction()
// Writing 'try' applies to both function calls.
sum = try (someThrowingFunction() + anotherThrowingFunction())
// Error: Writing 'try' applies only to the first function call.
sum = (try someThrowingFunction()) + anotherThrowingFunction()
A try expression can't appear on the right-hand side of an infix operator,
unless the infix operator is the assignment operator
or the try expression is enclosed in parentheses.
If an expression includes both the try and await operator,
the try operator must appear first.
For more information and to see examples of how to use try, try?, and try!,
see doc:ErrorHandling.
Grammar of a try expression:
try-operator →
try|try?|try!
Await Operator
An await expression consists of the await operator
followed by an expression that uses the result of an asynchronous operation.
It has the following form:
await <#expression#>
The value of an await expression is the value of the expression.
An expression marked with await is called a potential suspension point.
Execution of an asynchronous function can be suspended
at each expression that's marked with await.
In addition,
execution of concurrent code is never suspended at any other point.
This means code between potential suspension points
can safely update state that requires temporarily breaking invariants,
provided that it completes the update
before the next potential suspension point.
An await expression can appear only within an asynchronous context,
such as the trailing closure passed to the async(priority:operation:) function.
It can't appear in the body of a defer statement,
or in an autoclosure of synchronous function type.
When the expression on the left-hand side of an infix operator
is marked with the await operator,
that operator applies to the whole infix expression.
That said, you can use parentheses
to be explicit about the scope of the operator's application.
// Writing 'await' applies to both function calls.
sum = await someAsyncFunction() + anotherAsyncFunction()
// Writing 'await' applies to both function calls.
sum = await (someAsyncFunction() + anotherAsyncFunction())
// Error: Writing 'await' applies only to the first function call.
sum = (await someAsyncFunction()) + anotherAsyncFunction()
An await expression can't appear on the right-hand side of an infix operator,
unless the infix operator is the assignment operator
or the await expression is enclosed in parentheses.
If an expression includes both the await and try operator,
the try operator must appear first.
Grammar of an await expression:
await-operator →
await
Infix Expressions
Infix expressions combine an infix binary operator with the expression that it takes as its left- and right-hand arguments. It has the following form:
<#left-hand argument#> <#operator#> <#right-hand argument#>
For information about the behavior of these operators, see doc:BasicOperators and doc:AdvancedOperators.
For information about the operators provided by the Swift standard library, see Operator Declarations.
Note: At parse time, an expression made up of infix operators is represented as a flat list. This list is transformed into a tree by applying operator precedence. For example, the expression
2 + 3 * 5is initially understood as a flat list of five items,2,+,3,*, and5. This process transforms it into the tree (2 + (3 * 5)).
Grammar of an infix expression:
infix-expression → infix-operator prefix-expression
infix-expression → assignment-operator try-operator? await-operator? prefix-expression
infix-expression → conditional-operator try-operator? await-operator? prefix-expression
infix-expression → type-casting-operator
infix-expressions → infix-expression infix-expressions?
Assignment Operator
The assignment operator sets a new value for a given expression. It has the following form:
<#expression#> = <#value#>
The value of the expression is set to the value obtained by evaluating the value. If the expression is a tuple, the value must be a tuple with the same number of elements. (Nested tuples are allowed.) Assignment is performed from each part of the value to the corresponding part of the expression. For example:
(a, _, (b, c)) = ("test", 9.45, (12, 3))
// a is "test", b is 12, c is 3, and 9.45 is ignored
The assignment operator doesn't return any value.
Grammar of an assignment operator:
assignment-operator →
=
Ternary Conditional Operator
The ternary conditional operator evaluates to one of two given values based on the value of a condition. It has the following form:
<#condition#> ? <#expression used if true#> : <#expression used if false#>
If the condition evaluates to true,
the conditional operator evaluates the first expression
and returns its value.
Otherwise, it evaluates the second expression
and returns its value.
The unused expression isn't evaluated.
For an example that uses the ternary conditional operator, see doc:BasicOperators#Ternary-Conditional-Operator.
Grammar of a conditional operator:
conditional-operator →
?expression:
Type-Casting Operators
There are four type-casting operators:
the is operator,
the as operator,
the as? operator,
and the as! operator.
They have the following form:
<#expression#> is <#type#>
<#expression#> as <#type#>
<#expression#> as? <#type#>
<#expression#> as! <#type#>
The is operator checks at runtime whether the expression
can be cast to the specified type.
It returns true if the expression can be cast to the specified type;
otherwise, it returns false.
The as operator performs a cast
when it's known at compile time
that the cast always succeeds,
such as upcasting or bridging.
Upcasting lets you use an expression as an instance of its type's supertype,
without using an intermediate variable.
The following approaches are equivalent:
func f(_ any: Any) { print("Function for Any") }
func f(_ int: Int) { print("Function for Int") }
let x = 10
f(x)
// Prints "Function for Int".
let y: Any = x
f(y)
// Prints "Function for Any".
f(x as Any)
// Prints "Function for Any".
Bridging lets you use an expression of
a Swift standard library type such as String
as its corresponding Foundation type such as NSString
without needing to create a new instance.
For more information on bridging,
see Working with Foundation Types.
The as? operator
performs a conditional cast of the expression
to the specified type.
The as? operator returns an optional of the specified type.
At runtime, if the cast succeeds,
the value of expression is wrapped in an optional and returned;
otherwise, the value returned is nil.
If casting to the specified type
is guaranteed to fail or is guaranteed to succeed,
a compile-time error is raised.
The as! operator performs a forced cast of the expression to the specified type.
The as! operator returns a value of the specified type, not an optional type.
If the cast fails, a runtime error is raised.
The behavior of x as! T is the same as the behavior of (x as? T)!.
For more information about type casting and to see examples that use the type-casting operators, see doc:TypeCasting.
Grammar of a type-casting operator:
type-casting-operator →
istype
type-casting-operator →astype
type-casting-operator →as?type
type-casting-operator →as!type
Primary Expressions
Primary expressions are the most basic kind of expression. They can be used as expressions on their own, and they can be combined with other tokens to make prefix expressions, infix expressions, and postfix expressions.
Grammar of a primary expression:
primary-expression → identifier generic-argument-clause?
primary-expression → literal-expression
primary-expression → self-expression
primary-expression → superclass-expression
primary-expression → conditional-expression
primary-expression → closure-expression
primary-expression → parenthesized-expression
primary-expression → tuple-expression
primary-expression → implicit-member-expression
primary-expression → wildcard-expression
primary-expression → macro-expansion-expression
primary-expression → key-path-expression
primary-expression → selector-expression
primary-expression → key-path-string-expression
Literal Expression
A literal expression consists of either an ordinary literal (such as a string or a number), an array or dictionary literal, or a playground literal.
Note: Prior to Swift 5.9, the following special literals were recognized:
#column,#dsohandle,#fileID,#filePath,#file,#function, and#line. These are now implemented as macros in the Swift standard library:column(),dsohandle(),fileID(),filePath(),file(),function(), andline().
An array literal is an ordered collection of values. It has the following form:
[<#value 1#>, <#value 2#>, <#...#>]
The last expression in the array can be followed by an optional comma.
The value of an array literal has type [T],
where T is the type of the expressions inside it.
If there are expressions of multiple types,
T is their closest common supertype.
Empty array literals are written using an empty
pair of square brackets and can be used to create an empty array of a specified type.
var emptyArray: [Double] = []
A dictionary literal is an unordered collection of key-value pairs. It has the following form:
[<#key 1#>: <#value 1#>, <#key 2#>: <#value 2#>, <#...#>]
The last expression in the dictionary can be followed by an optional comma.
The value of a dictionary literal has type [Key: Value],
where Key is the type of its key expressions
and Value is the type of its value expressions.
If there are expressions of multiple types,
Key and Value are the closest common supertype
for their respective values.
An empty dictionary literal is written as
a colon inside a pair of brackets ([:])
to distinguish it from an empty array literal.
You can use an empty dictionary literal to create an empty dictionary literal
of specified key and value types.
var emptyDictionary: [String: Double] = [:]
A playground literal is used by Xcode to create an interactive representation of a color, file, or image within the program editor. Playground literals in plain text outside of Xcode are represented using a special literal syntax.
For information on using playground literals in Xcode, see Add a color, file, or image literal in Xcode Help.
Grammar of a literal expression:
literal-expression → literal
literal-expression → array-literal | dictionary-literal | playground-literalarray-literal →
[array-literal-items?,?]
array-literal-items → array-literal-item | array-literal-item,array-literal-items
array-literal-item → expressiondictionary-literal →
[dictionary-literal-items,?]|[:]
dictionary-literal-items → dictionary-literal-item | dictionary-literal-item,dictionary-literal-items
dictionary-literal-item → expression:expressionplayground-literal →
#colorLiteral(red:expression,green:expression,blue:expression,alpha:expression)
playground-literal →#fileLiteral(resourceName:expression)
playground-literal →#imageLiteral(resourceName:expression)
Self Expression
The self expression is an explicit reference to the current type
or instance of the type in which it occurs.
It has the following forms:
self
self.<#member name#>
self[<#subscript index#>]
self(<#initializer arguments#>)
self.init(<#initializer arguments#>)
In an initializer, subscript, or instance method, self refers to the current
instance of the type in which it occurs. In a type method,
self refers to the current type in which it occurs.
The self expression is used to specify scope when accessing members,
providing disambiguation when there's
another variable of the same name in scope,
such as a function parameter.
For example:
class SomeClass {
var greeting: String
init(greeting: String) {
self.greeting = greeting
}
}
In a mutating method of a value type,
you can assign a new instance of that value type to self.
For example:
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
Grammar of a self expression:
self-expression →
self| self-method-expression | self-subscript-expression | self-initializer-expressionself-method-expression →
self.identifier
self-subscript-expression →self[function-call-argument-list]
self-initializer-expression →self.init
Superclass Expression
A superclass expression lets a class interact with its superclass. It has one of the following forms:
super.<#member name#>
super[<#subscript index#>]
super.init(<#initializer arguments#>)
The first form is used to access a member of the superclass. The second form is used to access the superclass's subscript implementation. The third form is used to access an initializer of the superclass.
Subclasses can use a superclass expression in their implementation of members, subscripting, and initializers to make use of the implementation in their superclass.
Grammar of a superclass expression:
superclass-expression → superclass-method-expression | superclass-subscript-expression | superclass-initializer-expression
superclass-method-expression →
super.identifier
superclass-subscript-expression →super[function-call-argument-list]
superclass-initializer-expression →super.init
Conditional Expression
A conditional expression evaluates to one of several given values based on the value of a condition. It has one the following forms:
if <#condition 1#> {
<#expression used if condition 1 is true#>
} else if <#condition 2#> {
<#expression used if condition 2 is true#>
} else {
<#expression used if both conditions are false#>
}
switch <#expression#> {
case <#pattern 1#>:
<#expression 1#>
case <#pattern 2#> where <#condition#>:
<#expression 2#>
default:
<#expression 3#>
}
A conditional expression
has the same behavior and syntax as an if statement or a switch statement,
except for the differences that the paragraphs below describe.
A conditional expression appears only in the following contexts:
- As the value assigned to a variable.
- As the initial value in a variable or constant declaration.
- As the error thrown by a
throwexpression. - As the value returned by a function, closure, or property getter.
- As the value inside a branch of a conditional expression.
The branches of a conditional expression are exhaustive,
ensuring that the expression always produces a value
regardless of the condition.
This means each if branch needs a corresponding else branch.
Each branch contains either a single expression,
which is used as the value for the conditional expression
when that branch's conditional is true,
a throw statement,
or a call to a function that never returns.
Each branch must produce a value of the same type.
Because type checking of each branch is independent,
you sometimes need to specify the value's type explicitly,
like when branches include different kinds of literals,
or when a branch's value is nil.
When you need to provide this information,
add a type annotation to the variable that the result is assigned to,
or add an as cast to the branches' values.
let number: Double = if someCondition { 10 } else { 12.34 }
let number = if someCondition { 10 as Double } else { 12.34 }
Inside a result builder,
conditional expressions can appear
only as the initial value of a variable or constant.
This behavior means when you write if or switch in a result builder ---
outside of a variable or constant declaration ---
that code is understood as a branch statement
and one of the result builder's methods transforms that code.
Don't put a conditional expression in a try expression,
even if one of the branches of a conditional expression is throwing.
Grammar of a conditional expression:
conditional-expression → if-expression | switch-expression
if-expression →
ifcondition-list{statement}if-expression-tail
if-expression-tail →elseif-expression
if-expression-tail →else{statement}switch-expression →
switchexpression{switch-expression-cases}
switch-expression-cases → switch-expression-case switch-expression-cases?
switch-expression-case → case-label statement
switch-expression-case → default-label statement
Closure Expression
A closure expression creates a closure, also known as a lambda or an anonymous function in other programming languages. Like a function declaration, a closure contains statements, and it captures constants and variables from its enclosing scope. It has the following form:
{ (<#parameters#>) -> <#return type#> in
<#statements#>
}
The parameters have the same form as the parameters in a function declaration, as described in doc:Declarations#Function-Declaration.
Writing throws or async in a closure expression
explicitly marks a closure as throwing or asynchronous.
{ (<#parameters#>) async throws -> <#return type#> in
<#statements#>
}
If the body of a closure includes a throws statement or a try expression
that isn't nested inside of a do statement with exhaustive error handling,
the closure is understood to be throwing.
If a throwing closure throws errors of only a single type,
the closure is understood as throwing that error type;
otherwise, it's understood as throwing any Error.
Likewise, if the body includes an await expression,
it's understood to be asynchronous.
There are several special forms that allow closures to be written more concisely:
- A closure can omit the types
of its parameters, its return type, or both.
If you omit the parameter names and both types,
omit the
inkeyword before the statements. If the omitted types can't be inferred, a compile-time error is raised. - A closure may omit names for its parameters.
Its parameters are then implicitly named
$followed by their position:$0,$1,$2, and so on. - A closure that consists of only a single expression is understood to return the value of that expression. The contents of this expression are also considered when performing type inference on the surrounding expression.
The following closure expressions are equivalent:
myFunction { (x: Int, y: Int) -> Int in
return x + y
}
myFunction { x, y in
return x + y
}
myFunction { return $0 + $1 }
myFunction { $0 + $1 }
For information about passing a closure as an argument to a function, see doc:Expressions#Function-Call-Expression.
Closure expressions can be used
without being stored in a variable or constant,
such as when you immediately use a closure as part of a function call.
The closure expressions passed to myFunction in code above are
examples of this kind of immediate use.
As a result,
whether a closure expression is escaping or nonescaping depends
on the surrounding context of the expression.
A closure expression is nonescaping
if it's called immediately
or passed as a nonescaping function argument.
Otherwise, the closure expression is escaping.
For more information about escaping closures, see doc:Closures#Escaping-Closures.
Capture Lists
By default, a closure expression captures constants and variables from its surrounding scope with strong references to those values. You can use a capture list to explicitly control how values are captured in a closure.
A capture list is written as a comma-separated list of expressions
surrounded by square brackets,
before the list of parameters.
If you use a capture list, you must also use the in keyword,
even if you omit the parameter names, parameter types, and return type.
The last expression in the capture list can be followed by an optional comma.
The entries in the capture list are initialized
when the closure is created.
For each entry in the capture list,
a constant is initialized
to the value of the constant or variable that has the same name
in the surrounding scope.
For example in the code below,
a is included in the capture list but b is not,
which gives them different behavior.
var a = 0
var b = 0
let closure = { [a] in
print(a, b)
}
a = 10
b = 10
closure()
// Prints "0 10".
There are two different things named a,
the variable in the surrounding scope
and the constant in the closure's scope,
but only one variable named b.
The a in the inner scope is initialized
with the value of the a in the outer scope
when the closure is created,
but their values aren't connected in any special way.
This means that a change to the value of a in the outer scope
doesn't affect the value of a in the inner scope,
nor does a change to a inside the closure
affect the value of a outside the closure.
In contrast, there's only one variable named b ---
the b in the outer scope ---
so changes from inside or outside the closure are visible in both places.
This distinction isn't visible
when the captured variable's type has reference semantics.
For example,
there are two things named x in the code below,
a variable in the outer scope and a constant in the inner scope,
but they both refer to the same object
because of reference semantics.
class SimpleClass {
var value: Int = 0
}
var x = SimpleClass()
var y = SimpleClass()
let closure = { [x] in
print(x.value, y.value)
}
x.value = 10
y.value = 10
closure()
// Prints "10 10".
If the type of the expression's value is a class,
you can mark the expression in a capture list
with weak or unowned to capture a weak or unowned reference
to the expression's value.
myFunction { print(self.title) } // implicit strong capture
myFunction { [self] in print(self.title) } // explicit strong capture
myFunction { [weak self] in print(self!.title) } // weak capture
myFunction { [unowned self] in print(self.title) } // unowned capture
You can also bind an arbitrary expression to a named value in a capture list. The expression is evaluated when the closure is created, and the value is captured with the specified strength. For example:
// Weak capture of "self.parent" as "parent"
myFunction { [weak parent = self.parent] in print(parent!.title) }
For more information and examples of closure expressions, see doc:Closures#Closure-Expressions. For more information and examples of capture lists, see doc:AutomaticReferenceCounting#Resolving-Strong-Reference-Cycles-for-Closures.
Grammar of a closure expression:
closure-expression →
{attributes? closure-signature? statements?}closure-signature → capture-list? closure-parameter-clause
async? throws-clause? function-result?in
closure-signature → capture-listinclosure-parameter-clause →
()|(closure-parameter-list,?)| identifier-list
closure-parameter-list → closure-parameter | closure-parameter,closure-parameter-list
closure-parameter → closure-parameter-name type-annotation?
closure-parameter → closure-parameter-name type-annotation...
closure-parameter-name → identifiercapture-list →
[capture-list-items,?]
capture-list-items → capture-list-item | capture-list-item,capture-list-items
capture-list-item → capture-specifier? identifier
capture-list-item → capture-specifier? identifier=expression
capture-list-item → capture-specifier? self-expression
capture-specifier →weak|unowned|unowned(safe)|unowned(unsafe)
Implicit Member Expression
An implicit member expression is an abbreviated way to access a member of a type, such as an enumeration case or a type method, in a context where type inference can determine the implied type. It has the following form:
.<#member name#>
For example:
var x = MyEnumeration.someValue
x = .anotherValue
If the inferred type is an optional, you can also use a member of the non-optional type in an implicit member expression.
var someOptional: MyEnumeration? = .someValue
Implicit member expressions can be follo
…(truncated)