swiftrethrow

How to declare a rethrowing function?


I implemented the following function -as an extension of array of booleans- which could throw a CustomError error:

enum CustomError: Error {
    case empty
    case doesNotContainTrue
}

extension Array where Element == Bool {
    func indexOfFirstTrue() throws -> Int {
        if isEmpty { throw CustomError.empty }

        guard let detectedIndex = index(of: true) else {
            throw CustomError.doesNotContainTrue
        }

        return detectedIndex
    }
}

which works as expected:

let myArray = [false, true, false, true]
try print(myArray.indexOfFirstTrue()) // 1

Next, I tried to declare a function as:

func handleResult(_ index: Int) throws {
    print(index * 2)
    // ...
}

which should take the result of myArray.indexOfFirstTrue() and do something with it (for simplicity, let's assume that it prints the value multiplied by 2):

try handleResult(myArray.indexOfFirstTrue()) // 2

What I want to do is to declare handleResult as rethrowing function:

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.

The Swift Programming Language (Swift 4.1): Declarations - Rethrowing Functions and Methods.

So I can call it with non-throwing formula, thus it will not throws an error:

handleResult(myArray.indexOfFirstTrue()) // 2

But I am stuck of what should I edit to let it be a rethrowing function, so I tried to declare it as:

func handleResult(_ index: Int) rethrows {
    print(index * 2)
}

and I got the error of:

error: 'rethrows' function must take a throwing function argument

therefore, I also tried to declare it as:

func handleResult(_ index: (() throws ->  Int)) rethrows {
    print(index * 2)
}

and obviously got the error of:

error: cannot convert value of type 'Int' to expected argument type '() throws -> Int'

What should I do at this point?


Solution

  • Remember, the argument is of type () -> Int! So you need to call the function passed in to get the result! You also need try since the function can throw.

    func handleResult(_ index: (() throws ->  Int)) rethrows {
        print(try index() * 2) // see the "()"?
    }
    

    Now you can use it like this:

    let myArray = [true]
    try handleResult(myArray.indexOfFirstTrue)