How to use trailing closures and shorthand syntax?
  • July 29, 2025

1. Trailing Closure Syntax

When the last parameter to a function is a closure, you can write that closure after the function’s parentheses—without the parameter label. This is called a trailing closure.

Standard form

func performTask(times: Int, task: () -> Void) {
    for _ in 1...times {
        task()
    }
}

// Call without trailing closure:
performTask(times: 3, task: {
    print("Hello")
})

With trailing closure

// Trailing closure goes outside the (…):
performTask(times: 3) {
    print("Hello")
}

This reads more naturally when the closure is the main “action” you’re passing in.


2. Shorthand Closure Syntax

Swift can infer parameter types and return types from context, and you can:

  1. Omit types in the parameter list.
  2. Omit the return keyword when the body is a single expression.
  3. Use shorthand argument names ($0, $1, …) for positional parameters.

Full vs. shorthand example

let numbers = [1, 2, 3, 4, 5]

// Full form:
let doubledFull = numbers.map { (n: Int) -> Int in
    return n * 2
}

// Inferred types + implicit return:
let doubledInferred = numbers.map { n in
    n * 2
}

// Shorthand argument name:
let doubledShorthand = numbers.map { $0 * 2 }

3. Why Swift Has Trailing Closure Syntax

  • Readability: When the closure is the primary argument, moving it outside the parentheses highlights the work you want done.
  • Conciseness: It reduces visual clutter—especially for deeply nested calls (e.g., UIView.animate { … }).
  • Expressiveness: It feels more like natural language, e.g.
    UIView.animate(withDuration: 0.3) {
        view.alpha = 0
    }
    

4. When to Use Shorthand Parameter Names

  • Simple closures where the meaning of $0, $1, etc. is obvious.
  • Single-expression closures (no branching or multiple statements).
  • Inline transformations, e.g. map, filter, sorted(by:), where brevity improves readability.

Avoid shorthand when the closure body is complex, when you have more than 2–3 parameters, or when semantic names (from, to, value) would clarify intent.


5. Test: Shorthand Parameter Names

Paste this into a playground to verify you can use $0, $1 correctly:

// Test array of strings, sort by length using shorthand:
let words = ["swift", "closure", "trailing", "syntax"]
let sortedByLength = words.sorted { $0.count < $1.count }

assert(sortedByLength == ["swift", "syntax", "closure", "trailing"])
print("Test Passed: sortedByLength == \(sortedByLength)")

// Test mapping to optionals via shorthand:
let raw = ["1", "two", "3", "4a"]
let ints = raw.compactMap { Int($0) }
assert(ints == [1, 3])
print("Test Passed: ints == \(ints)")
  • Expected output:
    Test Passed: sortedByLength == ["swift", "syntax", "closure", "trailing"]
    Test Passed: ints == [1, 3]
    
    
    
    

    1. Accepting Functions (Closures) as Parameters

    In Swift you can pass functions or closures into other functions by specifying a function type as a parameter. The syntax is:

    func performOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) {
        let result = operation(a, b)
        print("Result is \(result)")
    }
    

    Here, operation is a parameter whose type is a closure taking two Ints and returning an Int.

    1.1 Calling with a Named Function

    func add(_ x: Int, _ y: Int) -> Int {
        return x + y
    }
    
    performOperation(4, 5, operation: add)  
    // Prints: Result is 9
    

    1.2 Calling with an Inline Closure

    performOperation(4, 5, operation: { (x, y) in
        x * y
    })
    // Prints: Result is 20
    

    2. Trailing Closure Syntax for Parameterized Closures

    If the last (or only) parameter is a closure, you can write it after the function call’s parentheses:

    performOperation(4, 5) { x, y in
        x - y
    }
    // Prints: Result is -1
    

    3. Why Pass Closures as Parameters?

    • Customization: Let callers inject behavior (sorting criteria, completion handlers, etc.).
    • Reusability: Write a single generic function and plug in different operations.
    • Asynchronicity: Provide callbacks to be executed later (network responses, animations).
    • Functional patterns: Chain and compose small bits of logic inline.

    4. Tests

    4.1 Test: Closures as Parameters

    // Define a function that applies a closure twice
    func applyTwice(to value: Int, using transform: (Int) -> Int) -> Int {
        return transform(transform(value))
    }
    
    // Test with a doubling closure
    let double = { (x: Int) -> Int in x * 2 }
    let result1 = applyTwice(to: 3, using: double)
    assert(result1 == 12)
    print("Test 4.1 Passed: applyTwice doubled twice == \(result1)")
    

    Expected output:
    Test 4.1 Passed: applyTwice doubled twice == 12


    4.2 Test: Trailing Closure Syntax

    // Reuse applyTwice but with a trailing closure that adds 5
    let result2 = applyTwice(to: 10) { $0 + 5 }
    assert(result2 == 20)
    print("Test 4.2 Passed: applyTwice with +5 twice == \(result2)")
    

    Expected output:
    Test 4.2 Passed: applyTwice with +5 twice == 20


    With these patterns you can accept, customize, and test functions/closures passed into your Swift APIs. Feel free to extend these examples to more parameters, different return types, or even throwing closures!

YOU MIGHT ALSO LIKE...
How to take action when a property changes

1. Taking Action When a Property Changes: Property Observers Swift lets you observe and respond to changes in a property’s ...

How to create your own structs? How to compute property values dynamically?

1. Creating Your Own Structs In Swift, a struct is a value type that you define with the struct keyword. ...

How to create and use closures?

1. What Is a Closure (and Why Swift Loves Them) A closure in Swift is a self-contained block of functionality ...

How to provide default values for parameters How to handle errors in functions

1. Providing Default Values for Function Parameters (Deep Dive) 1.1 Syntax and Ordering Declaration You assign a default right in ...

exyte

Concentric Onboarding iOS library for a walkthrough or onboarding flow with tap actions written with SwiftUI         Usage Create View's ...