Polyglot
Languages Swift operators
Swift § operators

Operators

Swift’s operator surface is C-family at the core: arithmetic, comparison, logical, bitwise. The principal additions: range operators (..< half-open and ... closed), nil-coalescing (??), optional chaining (?.), force-unwrap (!), type-cast (as, as?, as!), range and pattern matching (~= for case/when), and overflow operators (&+, &-, &* for explicit wrap-around). Swift admits operator overloading — types may define +, -, ==, etc. — and custom operators (declared with the operator keyword). The combination — the conventional C-family operators, the optional-handling operators, the range operators, the overflow-explicit forms — is the substance of Swift’s expression surface.

Arithmetic

a + b                                              // addition
a - b                                              // subtraction
a * b                                              // multiplication
a / b                                              // division (integer for ints, float for floats)
a % b                                              // remainder

-a                                                 // unary negation
+a                                                 // unary plus (rarely used)

Integer division truncates toward zero:

print(7 / 2)                                       // 3
print(-7 / 2)                                      // -3 (toward zero)
print(7 % 2)                                       // 1
print(-7 % 2)                                      // -1

For floating-point division, both operands must be float:

print(7.0 / 2.0)                                   // 3.5
print(7 / 2)                                       // 3 (Int)
print(Double(7) / Double(2))                       // 3.5

There is no ** (power) operator in Swift; use pow(_:_:) from Foundation:

import Foundation
pow(2.0, 10.0)                                     // 1024.0

For integer power, manual implementation or extensions are conventional.

Overflow behaviour

Swift traps on overflow by default:

let n = Int.max
let m = n + 1                                      // traps (runtime error)

For wrap-around, the overflow operators:

let n = Int.max
let m = n &+ 1                                     // Int.min (wraps)

// Also:
&-, &*

The default trapping eliminates substantial integer-overflow bugs.

Compound assignment

a += b                                             // a = a + b
a -= b
a *= b
a /= b
a %= b

a &+= b                                            // overflow add and assign
a &-= b
a &*= b

Comparison

a == b                                             // equality
a != b
a < b
a > b
a <= b
a >= b

Equality (==) requires the type to conform to Equatable:

struct Point: Equatable {
    let x: Int
    let y: Int
}

let p1 = Point(x: 1, y: 2)
let p2 = Point(x: 1, y: 2)
print(p1 == p2)                                    // true (synthesised)

The Equatable conformance is synthesised automatically for structs whose fields are all Equatable.

For ordering, the type must conform to Comparable:

struct Distance: Comparable {
    let meters: Double

    static func < (lhs: Distance, rhs: Distance) -> Bool {
        lhs.meters < rhs.meters
    }
}

[Distance(meters: 100), Distance(meters: 200)].sorted()

The < defines the ordering; Comparable derives <=, >, >=, ==.

Identity (===)

For reference types (classes), the === admits identity comparison (same object):

class Point {
    var x: Int
    init(x: Int) { self.x = x }
}

let p1 = Point(x: 1)
let p2 = Point(x: 1)
let p3 = p1

print(p1 === p2)                                   // false (different objects)
print(p1 === p3)                                   // true (same object)
print(p1 !== p2)                                   // true

The == (when defined) is value equality; === is identity. Treated in Value and reference types.

Logical operators

a && b                                             // AND (short-circuit)
a || b                                             // OR (short-circuit)
!a                                                 // NOT

The operands must be Bool; Swift does not admit truthiness:

let n: Int = 5
if n {                                             // ERROR: Int is not Bool
}
if n != 0 {                                        // OK
}

The strictness eliminates the C-family truthiness pitfalls.

Bitwise operators

a & b                                              // AND
a | b                                              // OR
a ^ b                                              // XOR
~a                                                 // NOT (unary)
a << b                                             // left shift
a >> b                                             // right shift (arithmetic for signed, logical for unsigned)

Swift’s right shift is arithmetic for signed integers (preserves sign) and logical for unsigned. For explicit logical shift on signed, the conversion idiom:

let n: Int8 = -1
let m = Int8(bitPattern: UInt8(bitPattern: n) >> 1)

Range operators

Two principal forms:

0..<10                                             // half-open: 0, 1, ..., 9
0...10                                             // closed: 0, 1, ..., 10

The half-open form is conventional for count-based iteration; the closed form for inclusive bounds:

for i in 0..<arr.count {                           // half-open admits all valid indices
    process(arr[i])
}

let weekday = 1...7                                // inclusive

One-sided ranges

let a = arr[0...]                                  // from 0 to end
let b = arr[..<3]                                  // up to (not including) 3
let c = arr[...]                                   // entire array

The forms admit substantial slicing flexibility.

Optional operators

Optional chaining ?.

The ?. admits “access this if non-nil”:

let name: String? = "Alice"
let length = name?.count                           // length is Int?

let user: User? = nil
let city = user?.address?.city                     // String?

let result = list?.first?.uppercased()             // String?

The form short-circuits on nil, returning nil for the entire expression.

Force unwrap !

The ! extracts the value or crashes if nil:

let name: String? = "Alice"
let length = name!.count                           // 5

let nilName: String? = nil
let oops = nilName!.count                          // CRASH: unexpectedly found nil

The conventional discipline avoids !if let, guard let, or nil-coalescing are conventionally safer.

Nil-coalescing ??

let name: String? = nil
let display = name ?? "anonymous"                  // "anonymous"

let port = config.port ?? 8080

The ?? admits “use the value, or this default if nil”.

For chained defaults:

let value = first ?? second ?? third ?? defaultValue

Type-cast operators

as (upcast)

let n: Int = 5
let any: Any = n as Any                            // upcast to Any (always succeeds)

as? (conditional cast)

let any: Any = "hello"

if let s = any as? String {
    print(s)                                       // "hello"
}

The as? returns Optional<T>nil if the cast fails.

as! (force cast)

let any: Any = "hello"
let s = any as! String                             // crashes on failure

The ! form is conventional only when the cast is guaranteed to succeed (typically by surrounding logic).

Type-check operator is

let any: Any = "hello"

if any is String {
    print("it's a string")
}

The is admits type-membership testing without binding.

Range and pattern operators

The ~= (range/pattern matching) admits switch/case matching:

let n = 5
switch n {
case 0:
    print("zero")
case 1...10:                                       // range pattern
    print("small")
case _ where n.isMultiple(of: 5):                  // where guard
    print("multiple of 5")
default:
    print("other")
}

The ~= is overloaded for ranges, optionals, and types. Treated in Pattern matching.

Custom operators

Swift admits custom operators:

infix operator **: MultiplicationPrecedence

func ** (base: Double, exponent: Double) -> Double {
    pow(base, exponent)
}

let result = 2.0 ** 10.0                           // 1024.0

The form: declare the operator (prefix, infix, postfix) with optional precedence; define the function.

The conventional discipline reserves custom operators for substantial use — they admit substantial expressiveness but reduce readability.

Operator overloading

Existing operators may be overloaded:

struct Vector {
    let x: Double
    let y: Double
}

extension Vector {
    static func + (a: Vector, b: Vector) -> Vector {
        Vector(x: a.x + b.x, y: a.y + b.y)
    }

    static func * (v: Vector, scalar: Double) -> Vector {
        Vector(x: v.x * scalar, y: v.y * scalar)
    }
}

let v = Vector(x: 1, y: 2) + Vector(x: 3, y: 4)

The mechanism admits substantial mathematical syntax for user types.

Operator precedence

Swift’s principal precedence levels (high to low):

OperatorsPrecedence
<<, >>BitwiseShift
*, /, %, &Multiplication
+, -, |, ^Addition
..<, ...Range
as, isCasting
??NilCoalescing
<, <=, >, >=, ==, !=Comparison
&&LogicalConjunction
||LogicalDisjunction
?:TernaryConditional
=, +=, etc.Assignment

The complete precedence is more substantial; the conventional discipline uses parentheses freely.

Common patterns

Optional default

let name = user?.name ?? "anonymous"
let port = config.port ?? 8080

Optional chaining

let firstChar = name?.first?.uppercased()
let result = users.first?.profile?.address?.city

Range iteration

for i in 0..<10 {
    process(i)
}

for c in "abc"..."xyz" {
    /* admitted but rarely useful */
}

Conditional cast

if let user = sender as? User {
    user.notify()
}

Tuple comparison

let a = (1, "alice")
let b = (1, "alice")
print(a == b)                                      // true (lexicographic on tuple components)

Range slicing

let arr = [1, 2, 3, 4, 5]
let first3 = arr[0..<3]                            // ArraySlice<Int>
let last2 = arr[3...]                              // ArraySlice<Int>
let middle = arr[1..<4]

Pattern matching with ~=

let n = 5
if 1...10 ~= n {
    print("in range")
}

The ~= admits explicit pattern matching outside switch.

Overflow check

let (sum, overflow) = a.addingReportingOverflow(b)
if overflow {
    // handle
}

The methods on integer types admit explicit overflow detection without the trap.

A note on the absence of ++ and --

Swift removed ++ and -- (in Swift 3) — the conventional defence:

n += 1
n -= 1

The increment-as-expression form (e.g., arr[i++] in C) is rare in Swift’s iteration patterns; the explicit += is the conventional form.

A note on the conventional discipline

The contemporary Swift operator advice:

  • Use == for value equality; === for identity (classes).
  • Use ?? over force-unwrap for default values.
  • Use ?. for optional chaining.
  • Use ! sparingly — only when the value is guaranteed non-nil.
  • Use as? over as! for casts that may fail.
  • Use ..< for half-open ranges; ... for closed.
  • Use &+, &-, &* for explicit wrap-around.
  • Implement operators via extensions for clean conformance.
  • Avoid custom operators unless substantively justified.

The combination — the conventional C-family operators, the optional-handling operators, the range and pattern operators, the overflow-trapping default with explicit wrap-around forms, the operator-overloading mechanism — is the substance of Swift’s expression surface. The discipline produces clear, type-safe expressions with substantial protection against the conventional integer and nil-pointer bugs.