A multiplatform Result monad for modelling success or failure operations.

Overview

kotlin-result

Maven Central CI Status License

Result<V, E> is a monad for modelling success (Ok) or failure (Err) operations.

Installation

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.michael-bull.kotlin-result:kotlin-result:1.1.13")
}

Introduction

The Result monad has two subtypes, Ok<V> representing success and containing a value, and Err<E>, representing failure and containing an error.

Mappings are available on the wiki to assist those with experience using the Result type in other languages:

Read More

Below is a collection of videos & articles authored on the subject of this library. Feel free to open a pull request on GitHub if you would like to include yours.

Getting Started

The idiomatic approach to modelling operations that may fail in Railway Oriented Programming is to avoid throwing an exception and instead make the return type of your function a Result.

fun checkPrivileges(user: User, command: Command): Result<Command, CommandError> {
    return if (user.rank >= command.mininimumRank) {
        Ok(command)
    } else {
        Err(CommandError.InsufficientRank(command.name))
    }
}

To incorporate the Result type into an existing codebase that throws exceptions, you can wrap functions that may throw with runCatching. This will execute the block of code and catch any Throwable, returning a Result<T, Throwable>.

val result: Result<Customer, Throwable> = runCatching {
    customerDb.findById(id = 50) // could throw SQLException or similar
}

Nullable types, such as the find method in the example below, can be converted to a Result using the toResultOr extension function.

val result: Result<Customer, String> = customers
    .find { it.id == id } // returns Customer?
    .toResultOr { "No customer found" }

Transforming Results

Both success and failure results can be transformed within a stage of the railway track. The example below demonstrates how to transform an internal program error (UnlockError) into an exposed client error (IncorrectPassword).

val result: Result<Treasure, UnlockResponse> =
    unlockVault("my-password") // returns Result<Treasure, UnlockError>
    .mapError { IncorrectPassword } // transform UnlockError into IncorrectPassword

Chaining

Results can be chained to produce a "happy path" of execution. For example, the happy path for a user entering commands into an administrative console would consist of: the command being tokenized, the command being registered, the user having sufficient privileges, and the command executing the associated action. The example below uses the checkPrivileges function we defined earlier.

tokenize(command.toLowerCase())
    .andThen(::findCommand)
    .andThen { cmd -> checkPrivileges(loggedInUser, cmd) }
    .andThen { execute(user = loggedInUser, command = cmd, timestamp = LocalDateTime.now()) }
    .mapBoth(
        { output -> printToConsole("returned: $output") },
        { error  -> printToConsole("failed to execute, reason: ${error.reason}") }
    )

Binding (Monad Comprehension)

The binding keyword allows multiple calls that each return a Result to be chained imperatively. When inside a binding block, the .bind() function is accessible on any Result. Each call to bind will attempt to unwrap the Result and store its value, returning early if any Result is an Err.

In the example below, should functionX() return an Err, then execution will skip both functionY() and functionZ(), instead storing the Err from functionX in the variable named sum.

fun functionX(): Result<Int, DomainError> { ... }
fun functionY(): Result<Int, DomainError> { ... }
fun functionZ(): Result<Int, DomainError> { ... }

val sum: Result<Int, DomainError> = binding {
    val x = functionX().bind()
    val y = functionY().bind()
    val z = functionZ().bind()
    x + y + z
}

println("The sum is $sum") // prints "The sum is Ok(100)"

The binding keyword primarily draws inspiration from Bow's binding function, however below is a list of other resources on the topic of monad comprehensions.

Coroutine Support

Use of suspending functions within a binding block requires an additional dependency:

dependencies {
    implementation("com.michael-bull.kotlin-result:kotlin-result:1.1.13")
    implementation("com.michael-bull.kotlin-result:kotlin-result-coroutines:1.1.13")
}

The coroutine implementation of binding has been designed so that the first call to bind() that fails will cancel all child coroutines within the current coroutine scope.

The example below demonstrates a computationally expensive function that takes five milliseconds to compute being eagerly cancelled as soon as a smaller function fails in just one millisecond:

suspend fun failsIn5ms(): Result<Int, DomainErrorA> { ... }
suspend fun failsIn1ms(): Result<Int, DomainErrorB> { ... }

runBlocking {
    val result = binding<Int, BindingError> {
        val x = async { failsIn5ms().bind() }
        val y = async { failsIn1ms().bind() }
        x.await() + y.await()
    }

    // result will be Err(DomainErrorB)
}

Inspiration

Inspiration for this library has been drawn from other languages in which the Result monad is present, including:

It also iterates on other Result libraries written in Kotlin, namely:

Improvements on the existing solutions include:

  • Feature parity with Result types from other languages including Elm, Haskell, & Rust
  • Lax constraints on value/error nullability
  • Lax constraints on the error type's inheritance (does not inherit from Exception)
  • Top level Ok and Err classes avoids qualifying usages with Result.Ok/Result.Err respectively
  • Higher-order functions marked with the inline keyword for reduced runtime overhead
  • Extension functions on Iterable & List for folding, combining, partitioning
  • Consistent naming with existing Result libraries from other languages (e.g. map, mapError, mapBoth, mapEither, and, andThen, or, orElse, unwrap)
  • Extensive test suite with almost 100 unit tests covering every library method

Example

The example module contains an implementation of Scott's example application that demonstrates the usage of Result in a real world scenario.

It hosts a ktor server on port 9000 with a /customers endpoint. The endpoint responds to both GET and POST requests with a provided id, e.g. /customers/100. Upserting a customer id of 42 is hardcoded to throw an SQLException to demonstrate how the Result type can map internal program errors to more appropriate user-facing errors.

Payloads

Fetch customer information

$ curl -i -X GET  'http://localhost:9000/customers/1'
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Content-Length: 84

{
  "firstName": "Michael",
  "lastName": "Bull",
  "email": "[email protected]"
}

Add new customer

$ curl -i -X POST \
   -H "Content-Type:application/json" \
   -d \
'{
  "firstName": "Your",
  "lastName": "Name",
  "email": "[email protected]"
}' \
 'http://localhost:9000/customers/200'
HTTP/1.1 201 Created
Content-Type: text/plain; charset=UTF-8
Content-Length: 16

Customer created

Contributing

Bug reports and pull requests are welcome on GitHub.

License

This project is available under the terms of the ISC license. See the LICENSE file for the copyright information and licensing terms.

Comments
  • Add iOS targets for kotlin mpp project

    Add iOS targets for kotlin mpp project

    Note: the ios() target is a shortcut to create targets for iosArm64(since ios11 all apps must be 64 bit) and iosX64(simulator) that will have any code in commonMain be depended on for code residing in iosMain. See https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#target-shortcuts for details.

    Note regarding publishing: the iOS artifacts must be compiled and deployed/published on a machine running macOS with full Xcode installed. see https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#using-kotlinnative-targets

    opened by Munzey 37
  • Clean up suspend binding implementation

    Clean up suspend binding implementation

    Also add more real-world test cases and improve its related readme section.

    Turns out that with the current implementation, if you launch coroutines inside the binding block and call bind inside one of those launched child coroutines then when the scope is cancelled these children coroutines aren't getting cancelled (they were basically being launched in the parent scope of binding so it had no effect).

    Correct solution is to make the lambda block of binding have a receiver of CoroutineScope. In this case that meant making SuspendableResultBinding implement CoroutineScope.

    This way we can launch the binding block inside an async coroutine where its context is used for SuspendableResultBinding (as its now also a CoroutineScope), so that when we cancel SuspendableResultBinding, we cancel the async coroutine and all its children.

    Also discovered that suspendCancellableCoroutine makes for a handy way to get around bind needing to throw in the error case for no reason. Think its a lot cleaner now.

    opened by Munzey 25
  • iosSimulatorArm64 and macOsArm64 support

    iosSimulatorArm64 and macOsArm64 support

    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 :)

    opened by slmlt 22
  • Move binding coroutine implementation to gradle subproject

    Move binding coroutine implementation to gradle subproject

    After some discussion in #28, it makes most sense to move the binding coroutines implementation to a subproject and have it published as a separate artifact that users will need to pull as a dependency for this feature.

    opened by Munzey 22
  • Binding doesn't support coroutines

    Binding doesn't support coroutines

    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.

    enhancement help wanted good first issue 
    opened by ditn 21
  • Multiplatform ArtifactNotFouundException

    Multiplatform ArtifactNotFouundException

    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!

    opened by andyburris 20
  • Add monad comprehensions via binding block with bind extension function

    Add monad comprehensions via binding block with bind extension function

    Hello!

    Thought I would open a pull request to add monad comprehension like syntax for this result type. Full disclosure: before i knew about this repo I had looked to adding this feature for result4k: https://github.com/npryce/result4k/pull/3 Wasn't getting a response there so I've moved on 😅 that's when I started looking around and found this very cool repo!

    For that pr I did quite a bit of micro benchmarking with jmh. The main reason for not moving forward with arrow's either type for me is how poor performing it is. The apis are also very unstable (still not at a 1.0 release). So it was important for me to choose another lib that was performant.

    With my (possibly contrived) test I have benchmarked and compared flatmapping versus using my proposed bind syntax for this repo. It came out a little slower:

    Lib | Success Flow | Failure Flow ------------ | ---------------- | ------------- ResultBinding | 187250 ops/ms | 178704 ops/ms flatmap | 280932 ops/ms | 258156 ops/ms

    One thing to point out is that comparing this library to Result4k, the ops/ms is significantly slower in this repo for flatmapping (i get around 250,000 - 280,000 ops/ms in this repo, compared to almost 450,000 ops/ms in result4k on my machine). I suspect its related to the use of contracts and more object creation in this repo. Regardless, its still pretty fast! just thought its interesting.

    Anyway, hope your open to the proposal and keeping well in these strange times!

    opened by Munzey 13
  • Kotlin multi-platform support

    Kotlin multi-platform support

    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.

    opened by SrgGrch 12
  • Concurrent failing binds causes uncaught BindException

    Concurrent failing binds causes uncaught BindException

    I was adding tests to check which error is returned when multiple binds fail for suspendable binding. I suspected that for async calls that finish closely there could be a race condition and you end up with the error from say, the second failed call instead of the first.

    Turns out there is a much bigger problem with implementation for async suspendable functions:

    runBlocking {
                val result = binding<Int, BindingError> {
                    val x = async { success().bind() }
                    val y = async { fails().bind() } // weird stuff happens here and an uncaught BindException occurs
                    val z = async { fails().bind() } 
                    x.await() + y.await() + z.await()
                }
    }
    

    Basically its not behaving with the different coroutines running concurrently. If you step through the test I've added returnsFirstErrIfBindingFailed() you'll see what I mean. Struggled to google a solution to this that could contain this to inside binding. This thread with an answer from Roman I thought would do the trick but still not working. CompletableDeferred might also be a solution but not sure how to incorporate it for this case.

    I tried a bunch of solutions. Mainly around seeing was there a hack I could implement creating a second ResultBinding implementation for SuspendableBinding. No luck. All out of ideas right now so hoping others can help jump on this 😄

    opened by Munzey 11
  • flatMap

    flatMap

    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!

    opened by Ravirael 11
  • Add iosSimulatorArm64 and macosArm64 targets

    Add iosSimulatorArm64 and macosArm64 targets

    This PR adds two missing targets which are required for projects which are built on Mac M1 chips. Currently any project targeting M1-targets and transitively depending on kotlin-result will not compile.

    I have tested on M1 Mac that ./gradlew assemble succesfully compiles and links the project. Tests for macosArm64 are passing too, but ./gradlew check currently fails on M1 Mac because it tries to run iosSimulatorArm64Test and it requires a running XCode & iOS simulator.

    Not sure how to best solve this for CI (in case it will be a problem).

    Closes #71.

    opened by dimsuz 9
  • Extensions for Kotlin Flow?

    Extensions for Kotlin Flow?

    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!):

    Some variants of Flow's 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()
            }
        }
    }
    

    Variant of 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
            }
        }
    }
    

    Variant of 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 {})

    opened by curioustechizen 7
  • Assertion helpers for tests

    Assertion helpers for tests

    Would you be open to adding helper functions for using Results 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()
    }
    
    help wanted 
    opened by ashughes 2
Releases(1.1.16)
  • 1.1.16(Apr 20, 2022)

    • Enable compatibility with non-hierarchical multiplatform projects (f0195b5d3f68784f21c5e14aeefc737bd2fc59cb)
      • See: https://github.com/michaelbull/kotlin-result/issues/71#issuecomment-1101608230
    Source code(tar.gz)
    Source code(zip)
  • 1.1.15(Apr 15, 2022)

    • Add iosSimulatorArm64 and macosArm64 targets by @dimsuz (fe30193d7c03c97f6a471adf251f71deb12152fb)
    • Update dependencies (96a84b227b1cbbe91a67bd1f0b2616da7e1a030a)
    • Update Gradle to 7.4.2 (ead48285598af63749ceb1056658fe85b4cc5ff9)
    • Include LICENSE file in META-INF directories of jar files (07ad45929f74dc207f7acf33eab6074c2bbaadb0)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.14(Jan 8, 2022)

    • Add getOrThrow by @Nimelrian (d07bd589edd24e55d18ec03036ac554e18fae025)
      • See #68
    • Migrate example project to Ktor 2 (6a5523c9983fb7852373b427e4f1c6a209cd9a64)
    • Update Gradle to 7.3.3 (7e89f1b6a6d2b09a5417893d352f8e557b05fc85)
    • Update dependencies (4b9ca158fc129c207a8f742b5fa7375879895f70)
    • Migrate to new kotlinx-coroutines-test API (72df4c0ff60979a3782ea8806ad853ee39c962b0)
      • See #69
    Source code(tar.gz)
    Source code(zip)
  • 1.1.13(Nov 2, 2021)

    • Update Kotlin to 1.5.31 by @pablisco (b8d4109eee92655745fd7750660ceea4def2cd50)
    • Replace usages of useExperimentalAnnotation by @grodin (4e1bb9d8de06ad30c3f3ca84bc6c00810587a72d)
    • Update Gradle to 7.2 (98c8eaead34fab3f1ae06cb357ebdc9761a555bc)
    • Add Result#orElseThrow (f236e2674bf98f12f50fa740e1f70aa65b5464d5)
    • Add Result#{throwIf,throwUnless} by @grodin (3b87373b238df613605cee0a82ee1e0def879507)
    • Add runSuspendCatching and T#runSuspendCatching by @grodin (2667273015dd18350d23f7a8de965cb49c184a8d)
      • See #64
    Source code(tar.gz)
    Source code(zip)
  • 1.1.12(Jun 12, 2021)

    • Add Linux, Windows and MacOS targets (c4c70b4d984c96693fe49ad5fa25035a6d99c965) by @avently
      • https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result-coroutines-linuxx64/
      • https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result-coroutines-macosx64/
      • https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result-coroutines-mingwx64/
    • Set JS compiler to BOTH (77942019c2eb8ccdff375819c97326c62e736948) by @gsteckman
    • Correctly cancel child jobs in suspending variant of binding (f2bd9aaa11915f2b20a41adc2543b98722b80027) by @Munzey
    • Fix typo in mapOr KDoc (32b1a9edb641c88249f0790420598e675c6ee4bf) by @mguelton
    • Update Kotlin to 1.5.10 (d64837f2f8171749ab391f9b40dcf10c11ec65f9) by @MrBergin
    Source code(tar.gz)
    Source code(zip)
  • 1.1.11(Feb 11, 2021)

    • Update Kotlin to 1.4.30 (d9662cc8e73cb4d843c2a6bfc9c2758551988675)
    • Add iOS build targets (ccb9c5b3aa567fdc33267ffb2fc420a6dbcd72b7) by @Munzey
      • https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result-iosx64/
      • https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result-iosarm64/
      • https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result-coroutines-iosx64/
      • https://repo.maven.apache.org/maven2/com/michael-bull/kotlin-result/kotlin-result-coroutines-iosarm64/
    • Move benchmarks to separate subproject (0df4c62d4f755d8e60197ad46d28bbf658c8173f) by @Munzey
    • Fix typo in recoverUnless kdoc (754aa5aaa4da22f875dac733c1fb51bbf21f2b92)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.10(Jan 30, 2021)

    • Releases are now automated via GitHub actions. Every push to master will produce a SNAPSHOT build available at:
      • https://oss.sonatype.org/content/repositories/snapshots/com/michael-bull/kotlin-result/kotlin-result/
    • Fixed links in README (3d40c7070837359a1e9884c56c1c6a7ec4dccb65) by @gregoryinouye
    • Eagerly cancel async bindings (c8372a052218a6d76a31b256968586093d0c03fb) by @Munzey
    • Add Result.recoverIf and Result.recoverUnless (0fdd0f2c2bccf3fdc6eb0615a145da4b6ee12ed5) by @oddsund
    • Publish JS multiplatform artifacts (0f90bb8b90c4fa224207ac40858856bce02b94fe) by @DerYeger
    Source code(tar.gz)
    Source code(zip)
  • 1.1.9(Aug 29, 2020)

    • Coroutine binding support moved to kotlin-result-coroutines module (b16fb559a14dcd77139fb907db213184581e6bd6) by @Munzey
      • See: https://github.com/michaelbull/kotlin-result/pull/28, https://github.com/michaelbull/kotlin-result/pull/29
    • Add Scala's merge (09d341ae6dc5222a15430e10adae5bcebd64f436)
      • Calling .merge() on a Result<List<Int>, Set<Int>> will return a Collection<Int> (their most common supertype).
    • Remove deprecation of eager-evaluating functions (a76768fa42ba0f0cc8ba07265d739007d4cd2370)
      • Rust includes these eager evaluating variants with a simple warning in their comments with regards to using the lazy variants for heavy lifting.
    • Update Gradle to 6.6.1 (30d2778d006c59c6b0a3faaee9cab5c4ab7fb3f1)
    • Update Kotlin to 1.4.0 (a662ebc0a7c838688e5b3e2d01707a29cde70456)
    • Use Kotlin 1.4's Explicit API mode (a9a0c384f45c57ed59feddb43914c7cb2e375a2d) by @Munzey
    Source code(tar.gz)
    Source code(zip)
  • 1.1.8(Jul 19, 2020)

    • Add suspend variant of binding function (bd7e1244b31e59e7d26479d7673d24716f70be0d) by @Munzey
      • Allows calls to binding to be passed a block that suspends
      • Addresses #24
    Source code(tar.gz)
    Source code(zip)
  • 1.1.7(Jun 28, 2020)

    • Add Result#toErrorIf (cf9582075db6b2e86e7c8bf09f18d255fe314443) by @Globegitter
      • Facilitates transforming an Ok to an Err if the value satisfies a given predicate.
    • Add Result#toErrorUnless (1000c588c01a6f1fa9133329c11681ecda112a95)
      • Facilitates transforming an Ok to an Err unless the value satisfies a given predicate.
    • Add monad comprehensions via binding block (9bcaa974ca03b9f518a1e84717f79272f4d090c2) by @Munzey
      • See the Binding section on the README for an introduction to this concept
    • Add benchmarking framework (0910e9ffe477a1daafbe1dd3fede452f2ae60bca) by @Munzey
    • Update Gradle to 6.5 (b4b2224ed24e63d9b26c4ed14dbbf2e751f91371)
    • Add unit tests for zip functions (31965ceb3d22ade6c7f45e63c289354cfaf16138) by @jvanderwee
    • Convert to multi-platform project structure (bca344daafadbc7af42089b88c712ac1061298dd) by @Munzey
    Source code(tar.gz)
    Source code(zip)
  • 1.1.6(Feb 12, 2020)

    • Update gradle to 6.2-rc-2 (e4da8cf75f7568d2cc4469a241d89e8f8aca8448)
    • Replace bintray with maven central (68cabd7a1e7967168211823679161bc7be1d7242)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.5(Jan 31, 2020)

    • Add kotlin.code.style=official to gradle.properties (6651b18905feebdbc445741168ee7128e18c5b5e)
    • Fix typo in Result#unwrap exception message (434b8aa7fbca71a0c234bb87e94f5d8e376fc36c)
      • Fixes #8
    • Add Rust's mapOr & mapOrElse (43ebd5753a2fb3810408c573fa09505e16930f4b)
      • See: https://blog.rust-lang.org/2020/01/30/Rust-1.41.0.html#library-changes
    • Replace code blocks in comments with variable references (4ed42cc40793eb485e1c61f7a082b6cea2a99c27)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.4(Dec 20, 2019)

    • Support destructuring declarations (1bf21253276c1715682e4c34be6284ec66a28158)
      • val (value: String?, error: Throwable?) = runCatching(yourFunction)
    • Update dependencies (782fac0cedddb102357888e6769ad61dd3d61fdb)
    • Replace travis with github actions (b3dbc36b7623afe5dea18d2090444bcf926bfd83)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.3(Aug 24, 2019)

    • Deprecate Result.of in favour of runCatching factory function (586b260683007d3a949d746c616ebc1abcdac449)
      • Matches Kotlin's stdlib and becomes top-level
    • Update Gradle to 5.6 (db00e6154211cfa111b19ef9b2b1c718fdb5d259)
    • Update dependencies (31808eb99cd0290da7f3850952c7ef1df7a92b9c)
    • Update "Creating Results" section in README (ed430c4eca1388da70d3f9c79c5ee0a3d7c46ff9)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.2(Aug 9, 2019)

  • 1.1.1(Nov 1, 2018)

    • Migrate to Kotlin Gradle DSL(80bd9dd69221ddec35cd81607ecacaa9cb28c96c)
    • Remove jdk dependency of kotlin stdlib (722ddd7c1fa353a13ba76e65cbdfb03796e88b70)
    • Update Kotlin to 1.3.0 (7e45bfb7f2d47cf43f2b1dd91e80979d144dc588)
    • Add fold as an alias to mapBoth (4eb5d80f9115578c63ce8360c240caaea2897e0c)
    • Return the Result in on{Success,Failure} (3a3b5415a748ad75bc133097e9d7b7cfd0d73cb8)
      • This facilitates chaining onSuccess/onFailure calls that may perform arbitrary side-effects, such as logging.
    • Add Result.recover (b5aab62af4f74a9a642f53a3c8f27bd47501bc32)
      • Similar to getOrElse but returns an Ok of the transformed error
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Sep 18, 2018)

    Now published on Bintray

    repositories {
        maven { url = 'https://dl.bintray.com/michaelbull/maven' }
    }
    
    dependencies {
        compile 'com.michael-bull.kotlin-result:kotlin-result:1.1.0'
    }
    
    • Update dependencies (cc1ab4940d63b73cc71b42ee3c2141f101c51513)
    • Add more mapping functions for Iterables (e43a7008d85284d2ce0342d9ed9b3681598b1a0a)
      • mapAll
      • mapResult
      • mapResultTo
      • mapResultNotNull
      • mapResultNotNullTo
      • mapResultIndexed
      • mapResultIndexedTo
      • mapResultIndexedNotNull
      • mapResultIndexedNotNullTo
    • Avoid creating unnecessary Err elements in map functions (29e21e57a0fc61c9a777b864694e838e89351bf4)
    • Consistently wrap documentation at 100 characters(1377350895c7a7e45a042308be39dc48feb368da)
    • Mark new mapping functions as inline (21db2e5e4f203f82bdb306eedf02283edd50237a)
    • Add bintray publishing configuration (4a0a49be904820f49f4124ea651337ee92b1ac0b)
    • Add explicit dependencies to bintrayUpload task (88f496a3664426a0eb853b2f52c6bfa2e4a2fe4a)
    • Migrate away from multi-platform project structure (f10de37b08a631f6d6d3ed102702e21066233666)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.8(Jan 24, 2018)

    • Fix mis-ordered modifier keywords (631f81d8ae6d2c42069a0f6ee8453cd707f0cf76)
    • Add toResultOr (410563b621d3e18860b1be92a07af9338d9274e1)
      • Acts as a factory function for converting nullable types to Results. An example is shown in the README.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.7(Jan 11, 2018)

    • Add zip functions (c2fc72d0cbc4ba62585bf2eff064fde010dceb6f)
    • Catch Exception instead of Throwable in Result.of (76870ef78a1fd7086d62a145d8e0834d0029d125)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.6(Jan 10, 2018)

    • Add lazy variants for {and,or,getOr,getErrorOr} (c6be93142d157acb1db155a393782ed912613a73)
    • Simplify doc comments according to Kotlin Coding Conventions (c5a11a914e730004f63f6e5f7a0ccbad57a054fe)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.5(Dec 17, 2017)

  • 1.0.4(Dec 16, 2017)

    • Mark on{Success,Failure} as infix (3e3b649193e58fb0707724fe260bcf38db54329a)
    • Inline the onSuccess() and onFailure() functions (47fa20ca34edfef10eeafb1861e9af04e6e56224)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.3(Dec 16, 2017)

    • Downgrade dokka (7b5ffefa8fb59f830ea02f1beea5807a5950a2cf)
    • Add multi-platform support (9ddac98e0c4d792536ed617cc586ffd9d04d1f41)
    • Update kotlin to 1.2.10 (416c0950b220365bb01279041bfad0d8cc7479da)
    • Update Gradle to 4.4 (64213f4b0496d561be8d6a9ae5a8432c560c3f95)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.2(Nov 28, 2017)

    • Upgrade Kotlin to 1.2.0 (8e3597322afdb2a8301d530f69c51f2d13dd523b)
    • Upgrade Gradle wrapper to (7c8fca30539aa77bf7b53600c86440cb54bd2fc6)
    • Make lambda return type of expect{Err} return Any (e455be2cc80b571aebf39079696a49a89bce8ad4)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Nov 22, 2017)

    • Add lazily evaluation to expect/expectError & deprecated older versions (ad7adacf395d62c8931fcf6f8dfb36bf0e94c9d1)
    • Add getErrorOrElse (5d5195af9deddf0bfd131aa3e0ad38766ce5544d)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Nov 22, 2017)

Owner
Michael Bull
Software developer & technology enthusiast with interests towards computer programming, reverse engineering, and full-stack web development.
Michael Bull
AppToDo is a simple Android project that performs the basic database CRUD operations that creates a todo task list

AppToDo is a simple Android project that performs the basic database CRUD operations that creates a todo task list

Rafiul Hye 1 Mar 13, 2022
Resultat is kotlin.Result with a loading state

What is Résultat? Résultat is a fork of Kotlin Result with a loading state. Why? Because sometimes you start a project based on Kotlin Result and you

null 41 Dec 10, 2022
Integration Testing Kotlin Multiplatform Kata for Kotlin Developers. The main goal is to practice integration testing using Ktor and Ktor Client Mock

This kata is a Kotlin multiplatform version of the kata KataTODOApiClientKotlin of Karumi. We are here to practice integration testing using HTTP stub

Jorge Sánchez Fernández 29 Oct 3, 2022
Kotlin Multiplatform String markup library

Thistle Kotlin multiplatform String markup library, inspired by SRML. Thistle is a common parser which produces an AST that can be rendered to a varie

Copper Leaf 52 Dec 30, 2022
Mobile client for official Nextcloud News App written as Kotlin Multiplatform Project

Newsout Android and iOS mobile client for Nextcloud news App. The Android client is already available to download in the Play Store. F-Droid and Apple

Simon Schubert 118 Oct 3, 2022
This Kotlin Multiplatform library is for accessing the TMDB API to get movie and TV show content. Using for Android, iOS, and JS projects.

Website | Forum | Documentation | TMDb 3 API Get movie and TV show content from TMDb in a fast and simple way. TMDb API This library gives access to T

Moviebase 37 Dec 29, 2022
KMMT : Kotlin Multiplatform Mobile Template

Kotlin Multiplatform Mobile App Template

Jitty Andiyan 206 Dec 22, 2022
SSU u-saint parser with Kotlin-Multiplatform and Ktor.

kusaint Soongsil University(SSU) u-Saint Parser with Kotlin Multiplatform. Prerequisites JVM !!IMPORTANT!! To run kusaint as a library in JVM environm

Hyomin Koo 3 Mar 23, 2022
Simple and extendable code highlighter in Kotlin Multiplatform

Kighlighter Simple and extendable code highlighter in Kotlin Multiplatform with a composable output to display the code highlighted on Android and Des

Gérard Paligot 21 Dec 2, 2022
Compile-time dependency injection for Kotlin Multiplatform

Kinzhal Kinzhal is a Kotlin Multiplatform library for compile-time dependency injection. The goal is to emulate basic features of Dagger to achieve si

Artem Daugel-Dauge 59 Dec 21, 2022
A simple MVI framework for Kotlin Multiplatform and Android

Orbit Multiplatform Get in touch What is Orbit Orbit is a Redux/MVI-like library - but without the baggage. It's so simple we think of it as MVVM+. Si

null 521 Jan 1, 2023
Create libraries for all types of Kotlin projects: android, JVM, Multiplatform, Gradle plugins, and so on.

JavierSC Kotlin template Create libraries for all types of Kotlin projects: android, JVM, Multiplatform, Gradle plugins, and so on. Features Easy to p

Javier Segovia Córdoba 2 Dec 14, 2022
Mocking for Kotlin/Native and Kotlin Multiplatform using the Kotlin Symbol Processing API (KSP)

Mockative Mocking for Kotlin/Native and Kotlin Multiplatform using the Kotlin Symbol Processing API (KSP). Installation Mockative uses KSP to generate

Mockative 121 Dec 26, 2022
Kotlin Multiplatform + Pizza = <3

KMPizza This repository accompanies a series of blog posts on the process of building an app with Kotlin Multiplatform. What is Kotlin Multiplatform?

Lena Stepanova 37 Nov 25, 2022
HelloKMM - Hello World in Kotlin Multiplatform Mobile (new empty project)

Hello KMM! Hello World in Kotlin Multiplatform Mobile (new empty project) Gettin

Blake Barrett 1 Feb 2, 2022
Kotlin-phoenix - A set of tools aimed to bridge Phoenix with the Kotlin Multiplatform world

Kotlin Phoenix This project is aimed to allow developers to work with Phoenix Ch

Adrien Jacquier Bret 5 Sep 21, 2022
FlowExt is a Kotlin Multiplatform library, that provides many operators and extensions to Kotlin Coroutines Flow

FlowExt | Kotlinx Coroutines Flow Extensions | Kotlinx Coroutines Flow Extensions. Extensions to the Kotlin Flow library | kotlin-flow-extensions | Coroutines Flow Extensions | Kotlin Flow extensions | kotlin flow extensions | Flow extensions

Petrus Nguyễn Thái Học 151 Jan 1, 2023
MMKV for Kotlin Multiplatform is a wrapper for MMKV using Kotlin API

MMKV for Kotlin Multiplatform is a wrapper for MMKV using Kotlin API

Ctrip, Inc. 65 Dec 29, 2022
A clean OpenAPI client generator for Kotlin multiplatform

kotlin-openapi-generator A not yet feature complete client generator. Features: generates 100% Kotlin multiplatform code does not generate any useless

Jakob K 5 Jun 6, 2022