tzortzik
tzortzik

Reputation: 5133

reuse logic in suspendable and nonsuspendable functions

The following two method contain the same functionality, the only difference is that one is suspendable and the other isn't (same for parameters).

How can I extract the implementation and reuse it for both functions?

fun validationWrapper(supplier: () -> Unit) = try {
    supplier.invoke()
} catch (ex: Exception) {
    when (ex) {
        is IllegalArgumentException, is IllegalStateException -> throw ValidationException(ex.message!!)
        else -> throw ex
    }
}

suspend fun validationWrapper(supplier: suspend () -> Unit) = try {
    supplier.invoke()
} catch (ex: Exception) {
    when (ex) {
        is IllegalArgumentException, is IllegalStateException -> throw ValidationException(ex.message!!)
        else -> throw ex
    }
}

I could keep only the suspendable function but that would mean I should use a runBlocking each time I use it.

Upvotes: 1

Views: 82

Answers (1)

Joffrey
Joffrey

Reputation: 37720

Keep the non-suspend version and make it inline. This solves the problem because the inlined lambda can then contain suspending calls without being declared suspend itself. It is how most of the Kotlin stdlib does this (forEach, map, etc.):

inline fun validationWrapper(supplier: () -> Unit) = try {
    supplier.invoke()
} catch (ex: Exception) {
    when (ex) {
        is IllegalArgumentException, is IllegalStateException -> throw ValidationException(ex.message!!)
        else -> throw ex
    }
}

Also, it is generally useful for higher-order functions that take lambdas to be declared inline, because it avoids extra costs of lambda instances.

Upvotes: 1

Related Questions