Note: Kotlin has since added Result
to its stdlib: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/index.html
A simple Result
monad for Kotlin.
Extracted from kog.
repositories {
maven { url "https://jitpack.io" }
}
dependencies {
compile "com.danneu:kotlin-result:x.y.z"
// Or always get latest
compile "com.danneu:kotlin-result:master-SNAPSHOT"
}
A Result
represents an outcome of an operation that can succeed or fail.
Result.Ok
wraps the output value:result.value
Result.Err
wraps the output error:result.error
The purpose of the abstraction is to provide a more functional
and composable way to handle errors than try/catch
.
For an example, check out kittinunf/Result#why.
val okResult = Result.ok(42)
val errResult = Result.err("failure")
Force-unwrap a result value.
Result.ok(42).getOrThrow() == 42
Result.err("failure").getOrThrow() // throws com.danneu.result.UnwrapException
Unwrap a result value with a fallback in case of error.
Result.ok(42).getOrElse(-1) == 42
Result.err("failure").getOrElse(-1) == -1
Or pass in a function if you want to inspect or transform the error.
Result.err("failure").getOrElse { message ->
message + "-transformed"
} == "failure-transformed"
Transform a result's value.
Result.ok(100).map { it + 1 } == Result.ok(101)
Result.err("failure").map { it + 1 } == Result.err("failure")
Transform a result's error.
Result.ok(100).mapError { it + "-mapped" } == Result.ok(100)
Result.err("failure").mapError { it + "-mapped" } == Result.err("failure-mapped")
Reduce both sides into a final value.
Result.ok(100).fold({ it + 1 }, { it + "-mapped" }) == 101
Result.err("failure").fold({ it + 1 }, { -1 }) == -1
Transform result into a new result based on its value.
Like .map()
except that the lambda returns a new result instead of a new value.
Result.ok(42).flatMap { Result.ok(100) } == Result.ok(100)
Result.err("failure").flatMap { Result.ok(100) } == Result.err("failure")
Transform result into a new result based on its error.
Like .mapError()
except that the lambda returns a new result instead of a new error.
Result.ok(42).flatMapError { Result.ok(100) } == Result.ok(42)
Result.err("failure").flatMapError { Result.ok(100) } == Result.ok(100)
Combine a list of results into a single result.
Short-circuits on first error.
Result.all(ok(1), ok(2), ok(3)) == Result.ok([1, 2, 3])
Result.all(ok(1), err("failure"), ok(3)) == Result.err("failure")
To represent a Result that can never fail, use Kotlin's Never
:
fun add (a: Int, b: Int): Result<Int, Never> {
return Result.ok(a + b)
}
Versus kittinunf/Result
kittinunf/Result is another Result monad library
implemented for Kotlin. However, it constrains
its Result value to non-null values and its error to instances
of Exception
.
This library does not constrain either types. This means that it can model nullable result values and errors represented as any type, like a simple string error message or an integer error code.
For example, you can represent Result<User?, String>
in this library
but not in kittinunf/Result.