iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🔡

Unique Syntax Features: Swift

に公開

This article is for day 8 of the Programming Language Specific Syntax Advent Calendar 2025.

I will introduce them based on my personal preferences.

Sample code for binary search

It is implemented specifically using language features.

// Swift - guard + where clause + optional chaining
func binarySearch<T: Comparable>(_ arr: [T], target: T) -> Int? {
    var (left, right) = (0, arr.count - 1)

    while left <= right {
        let mid = (left + right) >> 1

        switch arr[mid] {
        case let x where x == target: return mid
        case let x where x < target: left = mid + 1
        default: right = mid - 1
        }
    }
    return nil
}

let arr = [1, 3, 5, 7, 9]
print(binarySearch(arr, target: 5) ?? -1)  // 2

guard Statement

Explicitly check conditions with early returns and use variables outside the scope.

// Explicitly check conditions with early returns
func process(_ value: Int?) {
    guard let value = value else { return }
    guard value > 0 else { return }
    // value can be used as non-optional
    print(value)
}

// Multiple conditions
guard let x = optX, let y = optY, x > y else {
    return
}

switch + where Clause

Branching that combines pattern matching with additional conditions.

// Combination of pattern matching and conditions
switch value {
case let x where x < 0: print("negative")
case 0: print("zero")
case let x where x > 0: print("positive")
default: break
}

// Tuple matching
switch (x, y) {
case (0, 0): print("origin")
case (_, 0): print("on x-axis")
case (0, _): print("on y-axis")
case let (x, y) where x == y: print("diagonal")
default: print("other")
}

Optionals

A mechanism for expressing the possibility of a value's absence within the type system.

// Declare with ?, force unwrap with !
var name: String? = nil
name = "Alice"
print(name!)  // Force unwrap

// Optional binding
if let name = name {
    print(name)
}

// Optional chaining
let length = user?.profile?.name?.count

// Nil-coalescing operator
let displayName = name ?? "anonymous"

Tuples and Decomposition

Allows you to group multiple values to return them or assign them to multiple variables at once.

// Returning multiple values
func minMax(_ arr: [Int]) -> (min: Int, max: Int)? {
    guard let first = arr.first else { return nil }
    return arr.reduce((first, first)) { ($0.0.min($1), $0.1.max($1)) }
}

// Decomposition assignment
let (min, max) = minMax([1, 2, 3])!
var (left, right) = (0, arr.count - 1)

Trailing Closures

Syntax that allows a closure to be written outside the parentheses when it is the last argument.

// If the last argument is a closure, it can be placed outside
arr.filter { $0 > 0 }
    .map { $0 * 2 }
    .forEach { print($0) }

// Multiple trailing closures
UIView.animate(withDuration: 0.3) {
    view.alpha = 0
} completion: { _ in
    view.removeFromSuperview()
}

I personally really like this one.

$0, $1 (Shorthand Argument Names)

Implicit argument names that allow you to write closure arguments more concisely.

// Omit closure arguments
let doubled = arr.map { $0 * 2 }
let sum = arr.reduce(0) { $0 + $1 }
let sorted = arr.sorted { $0 > $1 }

defer

Defines a code block that is guaranteed to be executed when the current scope is exited.

// Always executed when the scope exits
func readFile() {
    let file = open("data.txt")
    defer { close(file) }  // Executed when the function ends

    guard let content = read(file) else { return }  // defer is executed here as well
    process(content)
}

// Multiple defers are executed in reverse order
defer { print("1") }
defer { print("2") }  // Output: 2, 1

I felt like readability might drop for a moment, but it seems good for grouping cleanup tasks like resource management.

willSet / didSet (Property Observers)

Allows you to execute code immediately before or after a property's value is changed.

var score: Int = 0 {
    willSet { print("Before change: \(score)\(newValue)") }
    didSet { print("After change: \(oldValue)\(score)") }
}

// Value validation in didSet
var percentage: Int = 0 {
    didSet { percentage = min(100, max(0, percentage)) }
}

KeyPath .

Allows references to properties to be treated as first-class objects.

// Treat property references as first-class objects
let names = users.map(\.name)  // Same as users.map { $0.name }
let sorted = users.sorted(by: \.age)

// Dynamic property access
struct User { var name: String; var age: Int }
let keyPath: KeyPath<User, String> = \.name
print(user[keyPath: keyPath])

some / any (Opaque Types / Existential Types)

Allows returning a type that conforms to a protocol while hiding the concrete type.

// some: Hides the concrete type (the compiler knows the type)
func makeShape() -> some Shape { Circle() }

// any: Existential type (can mix different types)
var shapes: [any Shape] = [Circle(), Rectangle()]

// Typical usage in SwiftUI
var body: some View {
    Text("Hello")
}

@resultBuilder (DSL Builder)

A feature that allows building declarative DSLs (Domain Specific Languages).

// Used in SwiftUI view construction
var body: some View {
    VStack {
        Text("Hello")
        Text("World")
        if showButton {
            Button("Tap") { }
        }
    }  // Declarative syntax that is neither an array nor a closure
}

A very interesting feature.

GitHubで編集を提案

Discussion