Some codes and contents are sourced from Apple’s official documentation. This post is for personal notes where I summarize the original contents to grasp the key concepts

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations/#Rethrowing-Functions-and-Methods

What is rethrows in Swift?

A function or method can be declared with the rethrows keyword to indicate that it throws an error only if one of its function parameters throws an error. These functions and methods are known as rethrowing functions and rethrowing methods. Rethrowing functions and methods must have at least one throwing function parameter.

Apple

Let’s check Foundation’s map function. A transform is a rethrowing function parameter.

It means transform function can throwing an error.

A rethrowing function or method can contain a throw statement only inside a catch clause. This lets you call the throwing function inside a docatch statement and handle errors in the catch clause by throwing a different error. In addition, the catch clause must handle only errors thrown by one of the rethrowing function’s throwing parameters. For example, the following is invalid because the catch clause would handle the error thrown by alwaysThrows().

A throwing method can’t override a rethrowing method, and a throwing method can’t satisfy a protocol requirement for a rethrowing method. That said, a rethrowing method can override a throwing method, and a rethrowing method can satisfy a protocol requirement for a throwing method.

Apple

alwaysThrows function is not a function parameter. In a someFunction, only callback function parameter can throwing a error.

enum SomeError: Error {
    case error
}

enum AnotherError: Error {
    case error
}

func alwaysThrows() throws {
    throw SomeError.error
}

Example 1. This one it working fine.

func someFunction(callback: () throws -> Void) rethrows {
    do {
        try callback()
    } catch {
        throw AnotherError.error
    }
}

Example 2. This one also working fine

func someFunction(callback: () throws -> Void) rethrows {
    try callback()
}

Example 3. This one compile error (A function declared ‘rethrows’ may only throw if its parameter does)

func someFunction(callback: () throws -> Void) rethrows {
    do {
        try alwaysThrows()
    } catch {
        throw AnotherError.error
    }
}

Because alwaysThrows function is not a part of someFunction’s parameter.

Example 4. Use try in a closure

When you use try in a closure, You should marked try someFunction

try someFunction {
    let decoder = JSONDecoder()
    try decoder.decode(String.self, from: Data())
    print("someFunction")
}

Example 5. Call a closure without using try

If you don’t use try in a closure, It’s okay not marking try at someFuntion.

If I change rethrows to throws in the example above, what happens?

There is a compile error. Always use try keyword when you call a someFunction.

Let’s make a customMap using rethrows keyword.

Built-In map function uses rethrows keyword.

var input = [1, 2, 3, 4, 5]

extension Array {
    func customMap<T>(_ transform: ((Element) throws -> T)) rethrows -> [T] {
        var result = [T]()
        for item in self {
            let transformedValue = try transform(item)
            result.append(transformedValue)
        }
        return result
    }
}

let output = input.customMap { item in
    "\(item)"
}

let output2 = input.map { item in
    "\(item)"
}

map itself uses try keyword. Because It allows users to use try in a closure. It we are not using try keyword in a closure we can simply use it without try keyword.

Leave a comment

Quote of the week

"People ask me what I do in the winter when there's no baseball. I'll tell you what I do. I stare out the window and wait for spring."

~ Rogers Hornsby