I have some code that looks like this:
data class MyStrings(val a: String, val b: String)
sealed class Error {
object SpecificError0 : Error()
object SpecificError1 : Error()
object SpecificError2 : Error()
}
fun either2(): Either<Error, String> =
Either.catch { throw RuntimeException("Either 2") }.mapLeft { Error.SpecificError2 }
fun either4(): Either<Error, MyStrings> =
Either.catch {
MyStrings(
a = "Hello",
b = either2().getOrElse { "" }
)
}.mapLeft { Error.SpecificError2 }
This will swallow the error from either2().
I'm trying to find a way to throw this error from either2 back if possible.
I know I can do something like this:
fun either5(): Either<Error, MyStrings> =
either2()
.flatMap {
Either.Right(
MyStrings(
a = "Hello",
b = it
)
)
}
but it seems strange to call something before I need it!
Any thoughts on how I can change either4()? Sorry if this is a n00b question, but I'm still trying to wrap my head around functional programming and Arrow.
Thank you.
kumbera,
In the last snippet you're not really calling it before you need it, but semantically it does look that way. Since MyStrings
depends on the result of either2()
, but we can rewrite it in a nicer way that scales much nicer without nesting callbacks.
You can improve these snippets by utilising Arrow's computation blocks, which allow extracting values out of Either
in a safe way.
fun either5(): Either<Error, MyStrings> = either.eager {
MyStrings(a = "Hello", b = either2().bind())
}
What happens here is that when you call bind
it will either return the value of Either.Right
, or it will immediately return the Either.Left
returned by either2()
as the result of either.eager
.
There is also a suspend
variant of the either
computation block that you can use directly as
suspend fun either6(): Either<Error, MyString> = either {
delay(100)
MyStrings(a = "Hello", b = either2().bind())
}
I hope that completely answers your question!