rednifre
03/14/2023, 6:31 PMsimon.vergauwen
03/14/2023, 6:49 PMalpha
.
either { }
required suspend
because it co-operates with Kotlin Coroutines. When it short-circuits on Either.Left.bind
it needs to cancel the Kotlin Coroutines it's potentially running inside of.
To avoid requiring suspend
when not running inside a Kotlin Coroutine you had to use either.eager
.
This is now solved by working more the inline
behavior of Kotlin, which automatically works with suspend
and inlines the same behavior as before into a Kotlin Coroutine when used inside of one.either { }
and either.eager { }
the new DSL is source compatible with the current one. So only requires changing package.rednifre
03/14/2023, 7:17 PMsimon.vergauwen
03/14/2023, 7:24 PMError2
you can create a common sealed interface
and since either
and Either
are covariant in E
you can do.
sealed class CommonError
object Error1 : CommonError
object Error2: CommonError
val x: Either<Error1, Int> = 1.right()
val y: Either<Error2, Int> = 1.right()
val sum = either.eager {
x.bind() + y.bind()
}
(Drop eager for alpha
version of Arrow)
If you don't control the errors:
• You can apply the same pattern but wrapping the original errors
• Resort to Either<Either<Error1, Error2>, Result>
With context receivers it's quite neat, but sadly those are still only experimental for JVM. In that case you can do something neat.
object Error1 : CommonError
object Error2: CommonError
val x: Either<Error1, Int> = 1.right() // fun Raise<Error1>.x(): Int = 1
val y: Either<Error2, Int> = 1.right() // fun Raise<Error1>.y(): Int = 1
context(Raise<Error1>, Raise<Error2>)
fun sum(): Int =
x.bind() + y.bind() // x() + y()
context(Raise<Error2>)
fun resolveError1(): Int =
recover({ sum() }) { err: Error1 -> 0 }
val sum: Either<Error1 | Error2, Int> = either {
x.bind() + y.bind()
}
context(Raise<Error1 | Error2>)
fun sum(): Int = x() + y()
rednifre
03/14/2023, 7:30 PMsealed interface Error1_2
sealed interface Error2_3
object Error1 : Error1_2
object Error2 : Error1_2, Error2_3
object Error3 : Error2_3
fun a(): Either<Error1_2, String>
fun b(): Either<Error2_3, String>
or what would be a good solution in that case?simon.vergauwen
03/14/2023, 7:32 PMDomainError
, and some smaller sealed interface
that inherit from the parent.
The errors of a layer form a sealed interface
and all the layers inherit from the top-most parent. That allows all errors to be combined conveniently as a travel through the layers.rednifre
03/14/2023, 7:34 PMsimon.vergauwen
03/14/2023, 7:39 PMUnexpected
all together from this hierachy.DomainError
or be removed all together. It's something I've used here to not throw any exceptions and then map to 500
but it should probably just stay an exception instead.
More details in this discussion: https://kotlinlang.slack.com/archives/C5UPMM0A0/p1678805582480059?thread_ts=1678801512.268339&cid=C5UPMM0A0rednifre
03/14/2023, 7:40 PMsimon.vergauwen
03/14/2023, 7:41 PM