10

It would be a basic question, but I couldn't figure out a solution. I need to initialize a constant out of the right-side value of below either type.

val test: Either<String, Int> = 1.right()

I tried something like below but it shrinks the scope of the constant.

when(test) {
        is Either.Right -> {val get:Int = test.b}
        is Either.Left -> println(test.a)
    }

I want that get to be scoped outside of when statement. Is there any way to do it or Arrow Either is not made for this purpose?

Vencat
  • 1,272
  • 11
  • 36
  • And what should `get` be if value is left? `null`? Use `when` as a statement. – Nicolas May 12 '20 at 20:45
  • @Nicolas edited my question. If I use when as expression then again I get into the same problem whether get gonnabe Int or String then kotlin choose *any* as type – Vencat May 12 '20 at 20:47
  • 1
    @Vencat in FP Either denotes code branching where both branches are possible. The only way to get rid of the left branch is to provide a value of the same type than the right one in that case. Look at LordRaydenMk's answer for this. Still that is not a convenient way to work. What you do in FP instead is keep it as an Either and compose the program operations on top, using combinators like map, flatMap etc as LordRaydenMk shows below. Those operate over the happy case (Right). Then at some point you plug an error handling strategy by calling fold() and handling errors on Left side. – Jorge Castillo May 13 '20 at 08:58

1 Answers1

14

The important question is: what should happen if the Either is Left. In this example it is created close to where it's used, so it is obvious to you as a developer. But to the compiler what is inside the Either can be either an Int or a String.

You can extract the value using for example fold:

val x = test.fold({ 0 }, {it}) // provide 0 as default in case the Either was a `Left`
// x = 1

another option is getOrElse

val test = 1.right()
val x = test.getOrElse { 42 } // again, default in case it was a `Left`
// x = 42

You can also work with it without unwrapping it:

val test = 1.right()
val testPlus10 = test.map { it + 10 } // adds 10 to `test` if it is `Right`, does nothing otherwise
val x = testPlus10.getOrElse { 0 } // unwrap by providing a default value
// x = 11

For more example check the official docs.

Recommended reading: How do I get the value out of my Monad

LordRaydenMK
  • 13,074
  • 5
  • 50
  • 56
  • 1
    This is a very accurate answer. The recommended approach would be the last one, where you keep it as an Either and stack operations on top of it, plugging a fold at some point for processing both sides. Some additional info about error handling using Either https://arrow-kt.io/docs/0.10/patterns/error_handling/#either – Jorge Castillo May 13 '20 at 06:25