Bird
Raised Fist0
Swiftprogramming~10 mins

Rethrowing functions in Swift - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Rethrowing functions
Call rethrowing function
↓
Call passed throwing closure
↓
Closure throws error?
No→Return normally
Yes↓
Rethrow error to caller
↓
Caller handles or propagates error
A rethrowing function calls a closure that can throw an error and only throws if that closure throws, passing the error up to its caller.
Execution Sample
Swift
enum MyError: Error {
    case example
}

func perform(action: () throws -> Void) rethrows {
    try action()
}

try perform {
    throw MyError.example
}
This code defines a rethrowing function that calls a throwing closure and rethrows any error it receives.
Execution Table
StepActionClosure Throws?Function Throws?Result
1Call perform with throwing closureN/AN/AEnter perform
2Inside perform, call action()YesYesError thrown from closure
3perform rethrows error to callerN/AYesError propagates out
4Caller handles error with tryN/AN/AError caught or propagated
💡 perform stops because closure throws, so perform rethrows and passes error to caller
Variable Tracker
VariableStartAfter Step 2After Step 3Final
actionclosure passedcalled and throws errorerror rethrownerror propagated
Key Moments - 2 Insights
Why does the perform function need the 'rethrows' keyword?
Because perform only throws if the closure it calls throws. The execution_table row 3 shows perform rethrowing the error it got from the closure.
What happens if the closure does NOT throw an error?
Then perform does not throw either and returns normally, as shown in execution_table row 2 where Closure Throws? would be No and Function Throws? would be No.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step does the closure throw an error?
AStep 1
BStep 2
CStep 3
DStep 4
💡 Hint
Check the 'Closure Throws?' column in execution_table row 2.
According to variable_tracker, what is the state of 'action' after Step 3?
AClosure called and error rethrown
BClosure called and completed without error
CClosure called and threw error
DClosure not called yet
💡 Hint
Look at variable_tracker row for 'action' after Step 3.
If the closure did not throw, what would change in the execution_table?
AFunction Throws? would be Yes at Step 2
BResult would be 'Error thrown from closure' at Step 2
CClosure Throws? would be No at Step 2
Dperform would still rethrow error at Step 3
💡 Hint
Refer to key_moments explanation about closure not throwing and execution_table row 2.
Concept Snapshot
Rethrowing functions use 'rethrows' keyword.
They only throw if the closure they call throws.
Use 'try' when calling the closure inside.
Errors from closure are passed up automatically.
Caller handles or propagates the error.
This avoids unnecessary throws if closure doesn't throw.
Full Transcript
This visual trace shows how a Swift rethrowing function works. The function 'perform' takes a closure that can throw an error. When 'perform' calls the closure, if the closure throws, 'perform' rethrows the error to its caller. The execution table shows each step: calling perform, calling the closure, closure throwing, perform rethrowing, and caller handling. The variable tracker shows the closure state changing from passed to called and throwing, then error rethrown. Key moments clarify why 'rethrows' is needed and what happens if the closure does not throw. The quiz tests understanding of when errors are thrown and how states change. The snapshot summarizes the main points about rethrowing functions in Swift.

Practice

(1/5)
1. What does the rethrows keyword indicate in a Swift function?
easy
A. The function cannot throw any errors.
B. The function always throws an error regardless of the closure.
C. The function only throws an error if the closure it receives throws an error.
D. The function catches all errors internally and never propagates them.

Solution

  1. Step 1: Understand the role of rethrows

    The rethrows keyword means the function itself does not throw errors unless the closure it accepts throws.
  2. Step 2: Compare options with this meaning

    The function only throws an error if the closure it receives throws an error. correctly states this behavior. Options B, C, and D misunderstand the conditional throwing nature of rethrows.
  3. Final Answer:

    The function only throws an error if the closure it receives throws an error. -> Option C
  4. Quick Check:

    rethrows means conditional throwing = A [OK]
Hint: Remember: rethrows means throw only if closure throws [OK]
Common Mistakes:
  • Thinking rethrows means always throws
  • Confusing rethrows with throws
  • Assuming rethrows catches errors
2. Which of the following is the correct syntax to declare a function that rethrows errors from a closure parameter named operation?
easy
A. func perform(operation: () -> Void) rethrows {}
B. func perform(operation: () rethrows -> Void) throws {}
C. func perform(operation: () throws -> Void) throws {}
D. func perform(operation: () throws -> Void) rethrows {}

Solution

  1. Step 1: Identify correct placement of throws and rethrows

    The closure parameter must be declared with throws if it can throw, and the function must be marked rethrows to propagate errors conditionally.
  2. Step 2: Check each option

    func perform(operation: () throws -> Void) rethrows {} correctly declares the closure as () throws -> Void and the function as rethrows. func perform(operation: () rethrows -> Void) throws {} incorrectly uses rethrows on the closure. func perform(operation: () throws -> Void) throws {} marks the function as throws instead of rethrows. func perform(operation: () -> Void) rethrows {} declares a non-throwing closure but marks the function as rethrows, which is invalid.
  3. Final Answer:

    func perform(operation: () throws -> Void) rethrows {} -> Option D
  4. Quick Check:

    Closure throws + function rethrows = A [OK]
Hint: Closure uses throws, function uses rethrows keyword [OK]
Common Mistakes:
  • Using rethrows on closure instead of function
  • Marking function as throws instead of rethrows
  • Marking function rethrows with non-throwing closure
3. What will be the output of the following Swift code?
func execute(task: () throws -> String) rethrows -> String {
    return try task()
}

func successTask() throws -> String {
    return "Success"
}

func failTask() throws -> String {
    throw NSError(domain: "Error", code: 1)
}

print(try execute(task: successTask))
medium
A. Success
B. Error thrown but caught silently
C. Compilation error due to rethrows misuse
D. Runtime crash without error handling

Solution

  1. Step 1: Understand function behavior with successTask

    The execute function calls task() which is successTask here. Since successTask returns "Success" without throwing, execute returns "Success".
  2. Step 2: Analyze output of print statement

    The print statement outputs the returned string "Success". No errors are thrown or caught here.
  3. Final Answer:

    Success -> Option A
  4. Quick Check:

    Successful closure call prints result = B [OK]
Hint: If closure succeeds, rethrowing function returns its result [OK]
Common Mistakes:
  • Assuming error is thrown when closure succeeds
  • Confusing rethrows with always throws
  • Expecting silent error handling
4. Identify the error in this Swift code snippet:
func run(operation: () throws -> Void) rethrows {
    do {
        try operation()
    } catch {
        print("Caught error")
    }
}

func risky() throws {
    throw NSError(domain: "Fail", code: 0)
}

try run(operation: risky)
medium
A. The function cannot be marked rethrows if it catches errors internally.
B. The closure parameter must not be marked throws.
C. The catch block should rethrow the error to propagate it.
D. The call to run must be inside a do-catch block.

Solution

  1. Step 1: Understand rethrows and error catching

    A function marked rethrows must not catch errors from the closure; it only propagates them. Catching errors inside breaks this rule.
  2. Step 2: Analyze the code's catch block

    The run function catches errors from operation() internally, so it cannot be marked rethrows. This causes a compile error.
  3. Final Answer:

    The function cannot be marked rethrows if it catches errors internally. -> Option A
  4. Quick Check:

    rethrows disallows internal catch = D [OK]
Hint: rethrows functions must not catch errors inside [OK]
Common Mistakes:
  • Marking function rethrows but catching errors inside
  • Confusing rethrows with throws
  • Expecting rethrows to handle errors silently
5. You want to write a Swift function processAll that takes an array of closures, each possibly throwing an error, and calls them all. If any closure throws, processAll should rethrow that error. Which is the best way to declare processAll?
hard
A. func processAll(tasks: [() throws -> Void]) rethrows { for task in tasks { try task() } }
B. func processAll(tasks: [() throws -> Void]) throws { for task in tasks { try task() } }
C. func processAll(tasks: [() -> Void]) rethrows { for task in tasks { task() } }
D. func processAll(tasks: [() throws -> Void]) { for task in tasks { try? task() } }

Solution

  1. Step 1: Understand rethrows limitation

    The rethrows keyword only works if the function takes exactly one throwing closure parameter. Here, tasks is an array of closures, so rethrows cannot be used.
  2. Step 2: Choose correct error propagation

    Since multiple closures can throw, processAll must be marked throws to propagate errors. func processAll(tasks: [() throws -> Void]) throws { for task in tasks { try task() } } correctly uses throws. func processAll(tasks: [() throws -> Void]) rethrows { for task in tasks { try task() } } incorrectly uses rethrows. func processAll(tasks: [() -> Void]) rethrows { for task in tasks { task() } } uses non-throwing closures. func processAll(tasks: [() throws -> Void]) { for task in tasks { try? task() } } ignores errors with try?.
  3. Final Answer:

    func processAll(tasks: [() throws -> Void]) throws { for task in tasks { try task() } } -> Option B
  4. Quick Check:

    Multiple throwing closures require throws, not rethrows = C [OK]
Hint: Use throws when multiple throwing closures are parameters [OK]
Common Mistakes:
  • Using rethrows with multiple throwing closures
  • Ignoring errors with try?
  • Declaring non-throwing closures when errors can occur
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard