I frequently end up with code like this:
fun foo(): Boolean {
try {
funcThatMightThrow()
} catch (e: Exception) {
logger.error("Error calling function: $e")
return false
}
// rest of function
}
And I’m looking for a way to make this shorter. One thing I’ve tried is changing funcThatMightThrow
to something like:
fun funcThatMightThrow(logger: Logger): Boolean {
try {
throwingFunc()
} catch (e: Exception) {
logger.error("Error: $e")
return false
}
return true
}
And then the caller looks like:
if (!funcThatMightThrow(logger)) {
return false
}
Which is better, but I find it a bit awkward/annoying to have to pass the logger into a helper function. What I really want is a syntax like this:
funcThatMightThrow().onException { e -> logger.error("Error: $e"); return }
I tried using eitherTry
/Either
for this, so I defined this extension function:
fun <L, R> Either<L, R>.ifError(block: (e: L) -> Unit) {
if (this is Either.Left<L, R>) {
block(this.l)
}
}
And then at the caller did:
eitherTry { funcThatMightThrow() }.ifError { e -> logger.error("Error!: $e"); return }
But I can’t return from the function (foo
) like that there, so then I tried:
fun <L, R> Either<L, R>.ifError(block: (e: L) -> Unit): Any? {
if (this is Either.Left<L, R>) {
block(this.l)
return null
}
return true
}
and the caller became:
eitherTry { funcThatMightThrow() }.ifError { e -> logger.error("error $e") } ?: return
Which works, but feels pretty deep into ugly hack territory. Is there a nice way of handling code like this?