Skip to content

A little library that provides an improved way to use `Result` in Kotlin

License

Notifications You must be signed in to change notification settings

PaoloConte/kotlin-itsok

Repository files navigation

badge badge badge badge badge badge badge badge badge badge badge badge badge

ItsOk

This is a little library that provides an improved way to use Result in Kotlin, with custom error types and also a way to avoid wrapping result objects into Ok and Error wrapper objects.

Why

There are two cool ways, in Kotlin standard library, to handle errors: kotlin.Result and sealed classes; though both present some limitations.
The standard Result uses exceptions as error type, which means you can't specify the type of possible error values.
With sealed classes you can define the set of both errors and ok values, but you lose the general flexibility and expressiveness of Result.

This library

This library aims to provide the best of both worlds, by providing a Result type that can be used with any type of error, and a set of extension functions to make it easier to work with it.
Furthermore, it provides two additional interfaces, ItsOk and ItsError which allow you to avoid wrapping results into Ok and Error objects, for cleaner and more efficient code.
Both the error and ok types can be a single class or multiple classes that all inherit from ItsOk and ItsError, especially useful to define in a sealed interface or sealed class.
See the example below to understand how it works.

Example

import io.paoloconte.itsok.*

sealed interface RepositoryError: ItsError<RepositoryError> {
    object NotFound : RepositoryError
    data class InvalidInput(val message: String) : RepositoryError
}

data class User(val name: String, val age: Int): ItsOk<User>

fun findUser(id: Int): Result<User, RepositoryError> {
    return if (id == 1)
        User("Mario", 30)           // no need to wrap in Ok
    else
        RepositoryError.NotFound    // no need to wrap in Error
}

fun main() {
    val result = findUser(1)
        .map { user ->
            user.name
        }
        .getOrElse {
            println("User not found")
            return
        }

    println("User name is -> $result")
}

Methods

fun <T, E> Result<T, E>.isOk(): Boolean 

fun <T, E> Result<T, E>.isError(): Boolean 

fun <T, E> Result<T, E>.getOrNull(): T? 

fun <T, E> Result<T, E>.getErrorOrNull(): E?

fun <T, E, R> Result<T, E>.map(transform: (T) -> R): Result<R, E>

fun <T, E, R> Result<T, E>.mapError(transform: (E) -> R): Result<T, R>

fun <T, E> Result<T, E>.recover(transform: (E) -> T): Result<T, E>

fun <T, E> Result<T, E>.onSuccess(block: Ok<T>.(T) -> Unit): Result<T, E> 

fun <T, E> Result<T, E>.onError(block: Error<E>.(E) -> Unit): Result<T, E> 

fun <T, E> Result<T, E>.getOrElse(onFailure: (E) -> T): T

fun <T, E> Result<T, E>.getOrDefault(defaultValue: T): T

fun <T, E, R> Result<T, E>.fold(onSuccess: (T) -> R, onError: (E) -> R): R

fun <T, E, R> Result<T, E>.flatMap(transform: Result<T, E>.(T) -> Result<R, E>): Result<R, E>

fun <T, E, R> Result<T, E>.flatMapError(transform: Result<T, E>.(E) -> Result<T, R>): Result<T, R>

fun <T, E, R> Result<T, E>.andThen(transform: Result<T, E>.(T) -> Result<R, E>): Result<R, E>  // same as flatMap

fun <T, E, F> Result<T, E>.orElse(onFailure: (E) -> Result<T, F>): Result<T, F>  // same as flatMapError

fun <T> resultCatching(block: () -> T): Result<T, Throwable> 

suspend fun <T> suspendCatching(block: suspend () -> T): Result<T, Throwable>

fun <T, E> Result<T, E>.getOrThrow(): T

fun <E> Result<Unit, E>.and(other: Result<Unit, E>): Result<Unit, E>

fun <T, E> Result<T, E>.or(other: Result<T, E>): Result<T, E>

Install

dependencies {
    implementation("io.paoloconte:kotlin-itsok:1.0.9")
}

About

A little library that provides an improved way to use `Result` in Kotlin

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages