2

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.

Somaiah Kumbera
  • 7,063
  • 4
  • 43
  • 44

1 Answers1

3

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!

nomisRev
  • 1,881
  • 8
  • 15
  • This is beautiful! Thank you. I assume the eager computational blocks also support multiple either binds? I currrently have mulitple flatmaps like this: either0() .flatMap { either1() } .flatMap{ either2() } and so on I assume these either1() and either2() calls can be made within the same eager block? Thank you so much for your answer, and your your contribution to Arrow. Its a beautiful library. – Somaiah Kumbera Feb 06 '22 at 11:38
  • 1
    Yes, it supports an infinite amount of `bind`s inside of `either { }`. You're very welcome & thank you for the kind compliment.! – nomisRev Feb 06 '22 at 11:45