michaelbull / kotlin-result Goto Github PK
View Code? Open in Web Editor NEWA multiplatform Result monad for modelling success or failure operations.
License: ISC License
A multiplatform Result monad for modelling success or failure operations.
License: ISC License
should be no need for ff87533
as with
already does this: https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/util/Standard.kt#L66
This can be useful at boundaries, like a rest or graphql handler. I've added an extension function, but this might be useful in the core library. I did a quick search and didn't find any related issues.
fun <V, E> Result<V, E>.getOrThrow(transform : (E) -> Throwable): V = getOrElse { error -> throw transform(error) }
edit: right now I'm using all of these.
fun <V, E> Result<V, E>.getOrThrow(transform: (E) -> Throwable) = getOrElse { throw transform(it) }
fun <V: Any?> V.success() = Ok(this)
fun <E: Any?> E.failure() = Err(this)
inline fun <V: Any, reified E: Throwable> trying(noinline block: () -> V) = trying(E::class, block)
fun <V, E: Throwable> trying(klass: KClass<E>, block: () -> V): Result<V, E> = try {
block().success()
} catch (e: Throwable) {
@Suppress("UNCHECKED_CAST")
when {
klass.isInstance(e) -> e.failure() as Err<E>
else -> throw e
}
}
Due to the heavy usage of extension functions, it's difficult to find this library's functionality by looking through source code in the IDE. Look through the source code on Github is seemingly the best option for now
Hi there, would you provide us any instruction on how to use the library in a multi-platform (JVM+JS) project?
Would you be open to adding helper functions for using Result
s in tests?
For example:
inline fun <reified V, reified E> Result<V, E>.assertOk(): V {
assertIs<Ok<V>>(this)
return value
}
Usage:
fun doSomething(): Result<String, Exception> {
// ...
}
@Test
fun test() {
val success: String = doSomething().assertOk()
}
I've tried to run gradlew check
locally but I'm encountering some odd issue that doesn't seem to happen on CI:
https://scans.gradle.com/s/xz4bgfv3rbzty/console-log?task=:kotlin-result:linkDebugTestIosX64
:kotlin-result:linkDebugTestIosX64 FAILED
e: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld invocation reported errors
Please try to disable compiler caches and rerun the build. To disable compiler caches, add the following line to the gradle.properties file in the project's root directory:
kotlin.native.cacheKind.iosX64=none
Also, consider filing an issue with full Gradle log here: https://kotl.in/issue
The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld command returned non-zero exit code: 1.
output:
ld: warning: ignoring file /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0/lib/darwin//libclang_rt.ios.a, missing required architecture x86_64 in file /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/13.0.0/lib/darwin//libclang_rt.ios.a (4 slices)
Undefined symbols for architecture x86_64:
"___cpu_model", referenced from:
polyHash_x86(int, unsigned short const*) in libstdlib-cache.a(result.o)
ld: symbol(s) not found for architecture x86_64
Could there be something I'm missing? I've tried opening the iOS emulator as I saw people with a similar error had seemed to work. Although I think native here is not necessarily targeting iOS.
I was trying to build the project but it looks like I may be missing some settings and fails when trying to evaluate Gradle:
i.e. should we change or offer the following as part of the api:
fun <V> binding(block: ResultBinding.() -> V): Result<V, *>
This would allow 2 things:
val result = binding {
val x = doSomething().bind()
val y = doSomethingElse().bind()
x + y
}
doSomething
and doSomethingElse
can have error types that dont extend from the same type.result
in the above example as Result<Int, *>
If we wanted to add this, would it make more sense to replace the current binding with this? or offer a second function. What would they be named? bindingAny
? bindingExplicit
?
Would you consider hosting artifacts not on Jitpack? Jitpack is convenient, but also a convenient mechanism for malicious code injection: artifacts are built somewhere, by some computer neither you (the author) nor me (the consumer) have anything to do with. This is more of a "Trust us, it's fine, probably" model than I'd prefer for artifact delivery.
Hosting release artifacts is pretty straightforward with Bintray, which I (and anyone else with an interest in verifiable artifacts) would prefer.
Since runCatching
catches all exceptions, it catches CancellationException
which prevents any coroutines launched within the runCatching
block from being cancelled when their enclosing CoroutineScope
is cancelled.
This is not, strictly speaking, an issue with kotlin-result but it caught me by surprise so I thought it would probably be good to warn others of the potential gotcha.
I propose:
kotlin-result-coroutines
called something like runSuspendCatching()
which rethrows CancellationException
.I've already written a version of runSuspendCatching()
and a test case that demonstrates the behaviour in my own project so I'm more than happy to submit a PR if you want.
The same issue has been raised for the stdlib runCatching
at Kotlin/kotlinx.couroutines#1814 but it doesn't seem like the Kotlin devs thinks it's much of a problem. I disagree and thought maybe we could at least improve things here!
See Roman's latest comment: https://youtrack.jetbrains.com/issue/KT-22228#focus=Comments-27-4791713.0-0
This is a great library and I'm using it for back- and frontend Kotlin code likewise!
One issue I have with it is that the IDE usually picks kotlin.Result as a default for the import and I have to manually add the com.github.michaelbull.result.Result import. Using Either
would be closer to the standard for what Result represents (not just closer, exactly spot on ;-). Thanks for considering.
Have you considered providing extensions for Kotlin Flows, specifically, Flow<Result<V, E>>
? I'm making heavy use of these "flows-of-result" and I have some helpers of my own. However, I feel that it would be much nicer to have binding
-style utilities that know about Flow
. Here are some examples of helpers that we have in our project (admittedly, some of these can have better names!):
combine
operators that know about Flow<Result<V, E>>
/**
* Variant of Kotlin's [combine] that makes it easier to work with flows of [Result].
*
* Use this if [transform] never returns an error. If your transform might return an error, consider using [combineResultWithErr] instead.
*/
fun <T1, T2, E, R> combineResult(
flow: Flow<Result<T1, E>>,
flow2: Flow<Result<T2, E>>,
transform: suspend (T1, T2) -> R
): Flow<Result<R, E>> {
return combine(flow, flow2) { r1, r2 ->
binding {
val s1 = r1.bind()
val s2 = r2.bind()
transform(s1, s2)
}
}
}
/**
* Variant of Kotlin's [combine] that makes it easier to work with flows of [Result].
*
* Use this if [transform] might return an error. If your transform never returns an error, consider using [combineResult] instead.
*/
fun <T1, T2, E, R> combineResultWithErr(
flow: Flow<Result<T1, E>>,
flow2: Flow<Result<T2, E>>,
transform: suspend (T1, T2) -> Result<R, E>
): Flow<Result<R, E>> {
return combine(flow, flow2) { r1, r2 ->
binding {
val s1 = r1.bind()
val s2 = r2.bind()
transform(s1, s2).bind()
}
}
}
andThen
that can be applied to a Flow<Result<V, E>>
/**
* Apply [transform] on each element in this [Flow] if the element is an [Ok] otherwise return the
* error as-is into the flow.
*/
fun <V, E, U> Flow<Result<V, E>>.andThen(transform: suspend (V) -> Result<U, E>): Flow<Result<U, E>> {
return map {
when (it) {
is Ok -> transform(it.value)
is Err -> it
}
}
}
flatMapLatest
that makes it simpler to work with Result<V, E>/**
* Like [andThen] but allows the [transform] to return a `Flow<Result>`. This method applies the
* [flatMapLatest] operator allowing you to return a flow from your transform
*/
fun <V, E, U> Flow<Result<V, E>>.andThenFlow(transform: suspend (V) -> Flow<Result<U, E>>): Flow<Result<U, E>> {
return flatMapLatest {
when (it) {
is Ok -> transform(it.value)
is Err -> flowOf(it)
}
}
}
As you can see, these utilities work, but they can be improved a lot. Specifically, they can benefit from the equivalent of binding {}
(perhaps something like flowBinding {}
)
Hello,
First of all, sorry for not fixing that typo in the PR i sent you ๐
A common pattern I see when wrapping library code is the following;
.andThen {
runCatching {
// lib code
}
}
The following creates an annoying typewarning, and looks wonky;
.map {
// code
}.runCatching {
if(this is Err) {
throw this.error
} else {
// lib code
}
}
Would you be willing to accept a PR for something like this? Name TBA, fire if you have any suggestions.
Also, would you place such a function in And.kt or Factory.kt?
.andThenCatching {
// lib code
}
I'm trying to import com.michael-bull.kotlin-result:kotlin-result:1.1.8
in the commonMain
source set in a multiplatform project, but the gradle build is failing with this stacktrace:
Gradle import errors
project ':web': Unable to build Kotlin project configuration
Details: org.gradle.internal.operations.BuildOperationQueueFailure: There was a failure while populating the build operation queue: Could not find kotlin-result-1.1.8-samplessources.jar (com.michael-bull.kotlin-result:kotlin-result:1.1.8).
Searched in the following locations:
https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result/1.1.8/kotlin-result-1.1.8-samplessources.jar
Caused by: org.gradle.internal.resolve.ArtifactNotFoundException: Could not find kotlin-result-1.1.8-samplessources.jar (com.michael-bull.kotlin-result:kotlin-result:1.1.8).Searched in the following locations:
https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result/1.1.8/kotlin-result-1.1.8-samplessources.jar
I'm using the same dependency in another (JVM-only) project and it works perfectly. Is there something I'm missing with multiplatform configuration that will solve this? Thanks!
So with Kotlin 1.5+, the Result type is finally "fully featured". I say that because, with the ability to use it as the return type for methods, it is truly viable as a functional error handling solution. However, having used Kotlin's Result and your Result, I must say that I like your API and feature set far better. However, a lot of the signatures class with Kotlin's (ie, their Result vs your Result) clash, so to use your library I typealias everything (ie, KtResult).
I think it would be wonderful if you were to refactor this to be built on top of the default Kotlin result, with all your great features (ie, flatMap, orElse, etc) as extension functions to it. I can see some challenges, namely that Result is a final class that cannot be extended (for Ok/Err), but I think that the outcome would be worth the effort.
Let me know your thoughts on this. I may be able to find some time to help you if you are interested.
PS. Obviously, given the scale of the breaking changes, you would have to either bump the major version, provide legacy API support, or create a separate 1.5+ artifact.
First of all, thanks for the great work!
As far as I understand I should be able to find the current version (com.michael-bull.kotlin-result:kotlin-result:1.1.8
) at maven central.
Unfortunately when looking there I only find the POM and checksum files, but not the JAR. Same for 1.1.7
.
Only for 1.1.6
I'm able to find the actual JAR on mane central.
Is this a misunderstanding from my side or where can I find the current JAR?
First of all, thanks for the nice result library you provide!
I would like to use the recoverIf function, which was introduced in one of the last PRs.
Is there a release due in the near future?
I have a method with this signature:
class MyException(override val message: String?, override val cause: Throwable?) : Exception(message, cause)
fun doSomething(): Result<String, MyException> {
val x: Result<String, MyException> = Result.of {
try {
"34"
} catch (e: Exception) {
throw MyException("some message", e)
}
}
}
I get a compilation error saying:
Error:(22, 19) Kotlin: Type inference failed. Expected type mismatch: inferred type is Result<String, kotlin.Exception /* = java.lang.Exception */> but Result<String, MyException> was expected
is it possible the problem is the definition of Result?
sealed class Result<out V, out E> {
companion object {
/**
* Invokes a [function] and wraps it in a [Result], returning an [Err]
* if an [Exception] was thrown, otherwise [Ok].
*/
inline fun <V> of(function: () -> V): Result<V, Exception> {
return try {
Ok(function.invoke())
} catch (ex: Exception) {
Err(ex)
}
}
}
}
It should not be something like:
inline fun of(function: () -> V): Result<V, out Exception> {
or perhaps I am missing something? I am new to kotlin-result and kotlin. So I cannot say...
I've noticed that certain APIs use "failure" terminology (onFailure
, fold(failure = )
, mapBoth(failure =)
), whereas others use "error" terminology (mapError
, getError
, toErrorIf
and more).
It looks like it would be more consistent to use "error" terminology across the board: onError
, fold(error = )
, mapBoth(error = )
+ any other APIs that I might be missing.
Hi, the documentation at https://github.com/michaelbull/kotlin-result/wiki/Elm#resultextracombine
could be updated to be more clear what happens when there is an error
val values = combine(
Ok(20),
Ok(40),
Ok(60)
).get()
// values = [ 20, 40, 60 ]
val error = combine(
Ok(20),
Err(40),
Ok(60)
)
// error = Err(40)
Hi!
I would've posted this in discussion if it was available, but I was curious if it had ever been considered to use coroutines instead of exceptions for the binding blocks.
Using exceptions has always seemed slightly error prone to me since all it takes is for someone to catch a generic exception and you now potentially have unexpected behavior. In addition stacktraces can be slightly expensive to produce.
On the flip side, coroutines have their drawbacks as well. For example, the stack traces can sometimes be confusing and there are limitations for where you can actually use bind.
For example I made a proof of concept and tried it out in a repo that made decent usage of binding. The issues are that any function that is not inline or suspend will produce a compilation error because you need to be within the custom coroutine context.
A map function is okay because it's inline, but a sequence function is not
listOf(1, 2, 3).asSequence().map {
provideX().bind()
}
Suspension functions can be called only within coroutine body
The other issue I discovered is when the binding context is put into the receiver of another function it fails as well (this is only an issue when restricting the scope of what suspend functions can be called from your scope).
run {
provideX().bind()
}
doesn't work but
kotlin.run {
provideX().bind()
}
In conclusion, I'm not convinced yet whether one solution is better than the other. I think the coroutine based approach has some benefits over the exception based approach, but it's slightly more restrictive in how you use it. I'm curious to know what you and others think! Thanks for your time.
Here's a link to my POC if you want to try it out. I made both a pure kotlin.coroutines version and a kotlinx.coroutines version.
dronda-t/kotlin-result@master...dronda-t:kotlin-result:dronda/kotlin-coroutines
When creating a domain entity with more than five fields (so zip is not available), the best pattern I've found goes like this:
data class T(val a: A, val b) {
companion object {
fun create(x1 : String?, x2: String?) : Result<T, DomainMessage> =
try {
Ok(T(
A.create(x1).unwrap(),
B.create(x2).unwrap()));
} catch (e:Exception) {
Err(ParseError("error: ${e.message}");
}
}
What I'd like to be able to do is return the original DomainMessage from the catch block:
} catch (e: UnwrapException) {
e.getErr()
}
Does this seem reasonable to you?
---- Edit: in proposed catch block, change Exception to UnwrapException
I tried to add a benchmark test for suspendable binding but ended up with cyclical dependencies trying to have kotlin-result
jvmBenchmark
source set depend on kotlin-result-coroutine
project (which already depends on kotlin-result
).
Would make life a lot easier to just move benchmarking to its own subproject. It would also simplify the current kotlin-result gradle file which has a bunch of tricks in it already just to get the benchmarking plugin to play nice inside an mpp build.
This would also help delineate dependencies if we decided to benchmark against other implementations (arrow's Either, kotlin's own result type, kittinunf's result type).
Once completed we can look to move the work in #27 to there.
I think it'd be nice to be able to write something like
val a = res.map { it.joinToString("\n") }.into_ok_or_err()
instead of
val a = when (res) {
is Ok -> res.unwrap().joinToString("\n") // -> String
is Err -> res.unwrapError() // -> String
}
This feature already exists in Rust Nightly.
It matches the signature of Haskell's Bifunctor.bimap
Hello
I am trying to add kotlin-result to my maven project, however strange things starts to happen then. After adding
<dependency>
<groupId>com.michael-bull.kotlin-result</groupId>
<artifactId>kotlin-result</artifactId>
<version>1.1.11</version>
</dependency>
Dependency is added, jar is downloaded , however I cannot import any class - maven just doesn't see classes from com.github.michaelbull package.
My properties for kotlin and java are:
<java.version>11</java.version>
<kotlin.version>1.4.31</kotlin.version>
Do you know what can cause such problems? I have never had such problem with any other library.
Are there any plans to include iOS Simulator and macOS running on Apple Silicon as kotlin native targets (iosSimultorArm64() and macOsArm64() targets)? This would greatly improve experience of KMM projects developers using this great library :)
I was excited to try out the binding
block in our codebase but it doesn't support suspending functions. We currently use Result
heavily with coroutines so this was a bit of a bummer. Is there any likelihood of this being added in the future? I'm not sure if it's out of scope for this project. I'm happy to raise a PR if you think it would be a worthwhile addition.
This question was already raised (here #5), but still, I am not able to use this library in the Multiplatform project. I think this is due to differences between the android library's build.gradle and the multiplatform one. In the MP library you need to specify kotlin("multiplatform")
plugin and divide code into source sets (for that specific library you will need only common source set). You can read more about [https://kotlinlang.org/docs/tutorials/mpp/multiplatform-library.html](Multiplatform Kotlin library) at kotlintlang.org
I've tested this library with MP "structure" and it seems to work, so if you are interested in supporting MP I can create PR for this and you will check out code.
Question rather than an issue: the docs in Iterable.kt
for e.g. getAll()
mention that the order is preserved. Other methods like combine()
don't mention anything about the order.
Is the order guaranteed and it's just that the docs are a bit inconsistent between methods or the order for some methods is not guaranteed?
Would it be possible/easy to add target mingwX86?
PS: thanks for such an elegant design.
I'm not really sure the best way to achieve this. It could very well be ignorance on my part.
I have an Android room table i want to Flow on. Something like: Flow<Vehicle>
First i need to get the userVehicleId from the User Repository. That isn't a flow, it returns Result<Int, Unit>
The function i have atm looks like this:
suspend fun getUserVehicle(): Flow<Result<Vehicle, Unit>>{
return userRepo.getUserVehicle() // returns `Result<Int, Unit> `
.andThen{ id ->
Ok(vehicleDao.flowOnUserVehicle(id)) // returns Flow<Vehicle, Unit>
}
}
This isn't valid and won't compile. Since I'm returning Result<Flow<Vehicle, Unit>
Thanks in advance!
I am getting an obscure error message when attempting to build my Android application after refactoring a Repository interface to return Result: e: Could not load module <Error module>
It's so vague that I can't think of where to look for what could be causing the error. I found this thread which suggests the error is caused by type inheritance failing.
I think you mean:
UnwrapException("called Result.unwrap on an Err value $error")
instead of
UnwrapException("called Result.wrap on an Err value $error")
Example computational expression from Scott Wlaschin's book:
The alternative (adding more versions of zip with more and more arguments) smells wrong. I noticed in your example service code you use runCatching in a very similar way to the code linked above.
Hello.
Currently, Result.orElse
has the following signature:
<V, E> Result<V, E>.orElse(transform: (E) -> Result<V, E>): Result<V, E>
However, it does not allow for changing the type of the error. Rust's or_else can change it, so how about modify it to align with that capability?
<T, E, F> Result<T, E>.orElse(transform: (E) -> Result<T, F>): Result<T, F>
thanks!
While wrapping calls to an external api, one pattern emerged - recoverIf. So it would be similar to toErrorIf
and toErrorUnless
, and would allow us to selectivly recover from known errors.
Is there any reason that this is not implemented? If not, I'll try to provide a PR during the weekend.
Hi,
I was looking at the code and it seems that the component1()
and component2()
methods in the Result
class are not really used anywhere.
I was wondering if they have any use that I'm failing to see here or if they could be removed.
Thanks.
Copying the following lines:
maven { url "https://jitpack.io" }
compile 'com.github.michaelbull:kotlin-result:1.1.0'
into the repositories
and dependencies
respectively generated a build error in Gradle.
Build error is as follows:
Warning:root project 'my_project': Unable to build Kotlin project configuration
Details: java.lang.reflect.InvocationTargetException: null
Caused by: org.gradle.api.artifacts.ResolveException: Could not resolve all dependencies for configuration ':compileClasspath'.
Caused by: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find com.github.michaelbull:kotlin-result:1.1.0.
Searched in the following locations:
https://repo1.maven.org/maven2/com/github/michaelbull/kotlin-result/1.1.0/kotlin-result-1.1.0.pom
https://repo1.maven.org/maven2/com/github/michaelbull/kotlin-result/1.1.0/kotlin-result-1.1.0.jar
https://jitpack.io/com/github/michaelbull/kotlin-result/1.1.0/kotlin-result-1.1.0.pom
https://jitpack.io/com/github/michaelbull/kotlin-result/1.1.0/kotlin-result-1.1.0.jar
Required by:
project :
The Elm page has this example:
val result = Err(500)
if (result is Error) {
println("Result is not ok")
}
I guess it should be
...
if (result is Err) {
...
I can't seem to find binding
even when is available as documentation on the front page. Is it available on 1.1.6?
Thanks
This is probably not an issue. Its more of a query i have. I very well could be misusing, misunderstanding or not aware of something.
The use case is if the api call fails i want it to successfully return the cache.
Much like andThen allows the transforming of one thing to another contained withing the Result type. What i feel i am looking for is a way to "andThen the error". So i can transform the E into a success using Ok(SomeType)
I can't find the function though i could just be using it wrong/this is not the correct practice.
For now i'm letting my Error contain any type so it can optionally return the result i want.
Thanks in advance, really loving using kotlin-result so far.
More of a general question rather than an issue.
We use andThen
extension quite a lot in our project to chain logic events.
I'm not very experienced in the functional world but If I would explain it in words is sort of "on a success execute this operation and transform into a new Result type"
Is there already any extension that would basically accomplish the reverse? Execute on an error and transform the result?
I'm facing a scenario where I want to try to recover from a failure. But the recovery itself could also still fail. So the code we have atm looks something like this:
Using these types as an example
fun foo(): Result<Int, String> = Err("FooError")
fun recoverFoo(): Result<Int, Int> = Ok(1)
We have this fold:
foo().fold(
success = { Ok(it) },
failure = {
recoverFoo()
.mapError { "FooRecoveryError" }
},
)
And I was hoping there would be a cleaner way to write it as maybe something like this:
foo().recoverError {
recoverFoo()
.mapError { "FooRecoveryError" }
}
And I guess if the method existed it would look something like this:
public inline infix fun <V, E, U> Result<V, E>.recoverError(transform: (V) -> Result<V, U>): Result<V, U> {
contract {
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}
return when (this) {
is Ok -> this
is Err -> transform(value)
}
}
So I guess my actual question is, with the existing extensions, is there a cleaner way to write this recovery scenario instead of using fold? I looked at mapError
but it forces the outcome to also be an Error, and that's not really the idea here, and I wasn't able to see any other alternatives.
Have you considered implementing a zipOrAccumulate
method, which unlike zip
, takes all of the Err
from the Result
arguments and returns them as Result<T, List<Err>>
?
zip
returns the first Err
from the Result
arguments, which can be inconvenient when we want to return multiple errors during validation.
For instance, when creating a user instance, if both the name and email address are invalid, we would want to return two errors.
class User(val name: Name, val email: Email) {
companion object {
fun create(name: String, email: String): Result<User, List<UserCreateError>> {
...
}
}
}
Arrow's Either has a zipOrAccumulate
method that can solve this problem.
https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#accumulating-different-computations
https://github.com/arrow-kt/arrow/blob/cb033637ab6b6f1f134b1924c948d6638cc5acf4/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt#L1499
As the implementation is not overly complicated, would you consider including it in kotlin-result?
Here's an example implementation: ZipOrAccumulate.kt
/**
* Apply a [transformation][transform] to ten [Results][Result], if both [Results][Result] are [Ok].
* If not, the all arguments which are [Err] will propagate through.
*/
public inline fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, E, Z> zipOrAccumulate(
producer1: () -> Result<T1, E>,
producer2: () -> Result<T2, E>,
producer3: () -> Result<T3, E>,
producer4: () -> Result<T4, E>,
producer5: () -> Result<T5, E>,
producer6: () -> Result<T6, E>,
producer7: () -> Result<T7, E>,
producer8: () -> Result<T8, E>,
producer9: () -> Result<T9, E>,
producer10: () -> Result<T10, E>,
transform: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) -> Z,
): Result<Z, Collection<E>> {
contract {
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer3, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer4, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer5, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer6, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer7, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer8, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer9, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer10, InvocationKind.AT_MOST_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}
val result1 = producer1()
val result2 = producer2()
val result3 = producer3()
val result4 = producer4()
val result5 = producer5()
val result6 = producer6()
val result7 = producer7()
val result8 = producer8()
val result9 = producer9()
val result10 = producer10()
return if (
result1 is Ok &&
result2 is Ok &&
result3 is Ok &&
result4 is Ok &&
result5 is Ok &&
result6 is Ok &&
result7 is Ok &&
result8 is Ok &&
result9 is Ok &&
result10 is Ok
) {
Ok(
transform(
result1.value, result2.value, result3.value,
result4.value, result5.value, result6.value,
result7.value, result8.value, result9.value,
result10.value,
),
)
} else {
Err(
listOf(
result1, result2, result3, result4,
result5, result6, result7, result8,
result9, result10,
).mapNotNull { (it as? Err)?.error },
)
}
}
public inline fun <T1, T2, E, Z> zipOrAccumulate(
producer1: () -> Result<T1, E>,
producer2: () -> Result<T2, E>,
transform: (T1, T2, T3) -> Z,
): Result<Z, Collection<E>> { ... }
public inline fun <T1, T2, T3, E, Z> zipOrAccumulate(
producer1: () -> Result<T1, E>,
producer2: () -> Result<T2, E>,
producer3: () -> Result<T3, E>,
transform: (T1, T2, T3) -> Z,
): Result<Z, Collection<E>> { ... }
public inline fun <T1, T2, T3, T4, E, Z> zipOrAccumulate(...
I can't see a flatMap
function or its equivalent which is typical for monads. It should work like Haskell's >>=
.
My suggested implementation:
infix inline fun <V, E, U> Result<V, E>.flatMap(transform: (V) -> Result<U, E>) : Result<U, E> {
return when (this) {
is Ok -> transform(value)
is Err -> this
}
}
Also flatMapError
function could be implemented in simillar way. If you like the idea, I will implement them along with unit tests and create a pull request.
Thanks!
Hello, I'm trying to build a KMP lib but I can't build the native variant (I've been able to build the other variants fine)
Execution failed for task ':compileKotlinNative'.
> Could not resolve all files for configuration ':nativeCompileKlibraries'.
> Could not resolve com.michael-bull.kotlin-result:kotlin-result:1.1.11.
Required by:
project :
> No matching variant of com.michael-bull.kotlin-result:kotlin-result:1.1.11 was found.
...
From what I understand, the mingwx64 variant of kotling-result seems to be missing for maven
https://search.maven.org/search?q=g:com.michael-bull.kotlin-result
Do you plan to add the mingwx64 artifact on maven in the future ?
Hi, in Java, it is generally consider a bad practice to catch Throwable instead of Exception due to Throwable being the super class of Error which represents lower level errors like OutOfMemory etc.
May I know is there any reason why runCatching is catching Throwable instead of Exception?
Arrow has a handy extension for eagerly returning from effect with an error if a value is null - ensureNotNull
. Would be very helpful to have a similar extension here, right now need to rely on fairly nested flatMap
:
val value = maybeGetValue()
.flatMap {
when (it) {
null -> Err(ValueMissingError)
else -> Ok(it)
}
}
.bind()
vs
val value = maybeGetValue().bind()
ensureNotNull(value) { ValueMissingError }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.