Operators
|
This section documents the Swift 6 language mode as shipped by Swift 6.3, as published in The Swift Programming Language at docs.swift.org, which is the reference these pages are written and verified against. 6.4-beta-only features are always flagged as such — never presented as baseline. This content was generated with the assistance of AI and should be verified against docs.swift.org before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Swift’s operator set is close to what a C-family language offers, plus range operators purpose-built for loops and slicing, and every operator’s exact precedence is queryable from a single, extensible table rather than memorized folklore.
Assignment
let b = 10
var a = 5
a = b // a is now 10
let (x, y) = (1, 2) // assignment also decomposes a tuple into multiple constants
Unlike C’s, Swift’s assignment operator does not itself return a value — if x = y { … } is a compile
error, which rules out the classic =-for-== typo entirely.
Arithmetic and Remainder
let sum = 1 + 2 // 3
let difference = 5 - 3 // 2
let product = 3 * 2 // 6
let quotient = 10.0 / 2.5 // 4.0
print("hello, " + "world") // + is also overloaded for String concatenation
let remainder = 9 % 4 // 1
print(-9 % 4) // -1 -- result takes the sign of the dividend, matching C's `%`
print(4 % -9) // 4
print(8.0.truncatingRemainder(dividingBy: 2.5)) // 0.5 -- % has no floating-point overload; use this instead
Unary plus (x`) is a no-op provided purely for symmetry with unary minus (`-x`); overflow on `/-///
*traps by default (a runtime crash), unlike C’s silent wraparound — see the &+/&-/&* overflow
operators in Advanced Operators for the opt-in
wrapping versions.
Compound Assignment
var a = 1
a += 2 // a = a + 2, now 3
a -= 1
a *= 4
a /= 2
A compound-assignment operator’s result cannot itself be used as a value — let b = (a += 2) does not
compile — which differs from C’s compound assignment.
Comparison Operators
print(1 == 1) // true
print(2 != 1) // true
print(2 > 1) // true
print(1 < 2) // true
print(1 >= 1) // true
print(2 <= 1) // false
let tuple1 = (1, "zebra")
let tuple2 = (2, "apple")
print(tuple1 < tuple2) // true -- compares 1 against 2 first; the strings are never reached
print((1, "zebra") < (1, "apple")) // false -- first elements tie, so the second elements decide
Tuples compare left to right, element by element, short-circuiting at the first pair that differs; Swift
provides these comparison operators for tuples of up to six elements out of the box, and every element’s type
must itself be Comparable (or, for ==/!=, Equatable).
The Ternary Conditional Operator
let contentHeight = 40
let hasHeader = true
let rowHeight = hasHeader ? contentHeight + 50 : contentHeight + 20 // 90
question ? answer1 : answer2 is shorthand for a two-branch if/else that produces a value; exactly one of
answer1/answer2 is evaluated. Nested ternaries read poorly fast — prefer a plain if/else expression
(Swift 5.9+) or a switch once a condition gets past one level.
Nil-Coalescing
let defaultColorName = "red"
let userDefinedColorName: String? = nil
let colorNameToUse = userDefinedColorName ?? defaultColorName // "red"
a ?? b unwraps a if non-nil, otherwise evaluates b; it is covered in full, alongside every other way to
work with optionals, in Optionals.
Range Operators
for index in 1...5 { print(index) } // 1 2 3 4 5 -- closed range, includes both ends
let names = ["Anna", "Alex", "Brian", "Jack"]
for i in 0..<names.count { print(names[i]) } // half-open range, excludes the upper bound -- the usual array-index range
print(names[2...]) // ["Brian", "Jack"] -- one-sided range: from index 2 to the end
print(names[...2]) // ["Anna", "Alex", "Brian"] -- one-sided range: from the start through index 2
print(names[..<2]) // ["Anna", "Alex"] -- one-sided, half-open
for name in names[1...2] { print(name) } // one-sided/closed ranges work as subscripts and as sequences alike
print((1...5).contains(3)) // true -- a range is a real value, testable with `contains`
// let backwards = 5...1 // runtime error: a closed range's lower bound must be <= its upper bound
A closed range (a…b) includes both endpoints; a half-open range (a..<b) excludes the upper bound and
is the natural fit for zero-based array indices; a one-sided range (a…, …b, ..<b) is a range
Swift infers as far as context allows — typically "to the end" or "from the start" of a collection.
Logical Operators
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
print("Welcome!")
} else {
print("ACCESS DENIED") // printed -- && short-circuits, evaluated left to right
}
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
print("Welcome!") // printed -- || also short-circuits
}
print(!enteredDoorCode) // false -- logical NOT
&& and || are short-circuiting: the right operand is evaluated only if the left one leaves the result
undetermined, which means a right-hand side with a side effect (a function call) may not run at all — exactly
like C, Java, or JavaScript.
Explicit Parentheses
let result = 2 + 3 % 4 * 5 // 17, following the precedence table below -- but is that clear at a glance?
let clearer = 2 + ((3 % 4) * 5) // also 17, spelled out
Swift lets every operator’s precedence resolve an unparenthesized expression unambiguously, but that does not
make it readable — adding parentheses purely for clarity, even where they change nothing, is idiomatic
Swift wherever a mix of operator kinds (bitwise with arithmetic, ?? with comparison, && with ||) could
make a reader stop and think.
Precedence and Associativity
Every operator belongs to a precedence group, and each group has an explicit relative ordering to every other group plus its own associativity — the table below lists the standard library’s groups from highest to lowest:
| Precedence group | Representative operators | Associativity |
|---|---|---|
|
|
none |
|
|
left |
|
|
left |
|
|
none |
|
|
none |
|
|
right |
|
|
none |
|
|
left |
|
|
left |
|
most custom operators land here if unspecified |
— |
|
|
right |
|
|
right |
infix operator +-: AdditionPrecedence
func +- (left: Int, right: Int) -> Int { left + right - right }
// declares a custom operator explicitly slotted into an existing precedence group
A group with associativity none cannot be chained without parentheses at all — 1 < 2 < 3 is a compile
error, unlike a language where comparisons quietly chain or coerce to booleans. Declaring a custom operator’s
own precedencegroup, with higherThan/lowerThan relations to existing groups, is covered alongside every
other advanced-operator feature in
Advanced Operators.
See Also
-
Optionals —
??, optional chaining, and the optional pattern. -
Basics: Constants, Variables and Types — the numeric types these operators act on.
-
Pattern Matching —
~=, the pattern-match operator behindswitch/case. -
Advanced Operators — overflow operators, bitwise operators, and defining custom operators and precedence groups.