Skip to content

Instantly share code, notes, and snippets.

@rr-codes
Created October 15, 2021 18:37
Show Gist options
  • Save rr-codes/b3b3b961cb1fbeeaaf6e536ffc63d4d9 to your computer and use it in GitHub Desktop.
Save rr-codes/b3b3b961cb1fbeeaaf6e536ffc63d4d9 to your computer and use it in GitHub Desktop.
/**
* Apple's `Result` type ported to Kotlin. Instead of using enums with associated values, this implementation uses a
* sealed interface with implementations.
*
* ```
* /* create a Result */
*
* fun makeResult() = Result { // throw a `Throwable` or return a value }
*
* fun generateRandomNumber(maximum: Int): Result<Int, IllegalArgumentException> {
* return if (maximum < 0) {
* Result.failure(IllegalArgumentException("$maximum < 0"))
* } else {
* val n = Random.nextInt(maximum)
* Result.success(n)
* }
* }
*
* /* use the Result */
* when (r) {
* is Result.Success -> // do something with `r.value`
* is Result.Failure -> // do something with `r.reason`
* }
* ```
*
* @author Richard Robinson
*/
sealed interface Result<out S, out F: Throwable> {
data class Success<S>(val value: S) : Result<S, Nothing> {
override fun get(): S = value
override fun <NewSuccess> map(
transform: (S) -> NewSuccess
): Result<NewSuccess, Nothing> = Success(transform(value))
override fun <NewFailure : Throwable> mapError(
transform: (Nothing) -> NewFailure
): Result<S, NewFailure> = this
override fun <NewSuccess> flatMap(
transform: (S) -> Result<NewSuccess, Nothing>
): Result<NewSuccess, Nothing> = transform(value)
override fun <NewFailure : Throwable> flatMapError(
transform: (Nothing) -> Result<S, NewFailure>
): Result<S, NewFailure> = this
}
data class Failure<F: Throwable>(val reason: F) : Result<Nothing, F> {
override fun get(): Nothing = throw reason
override fun <NewSuccess> map(transform: (Nothing) -> NewSuccess): Result<NewSuccess, F> = this
override fun <NewFailure : Throwable> mapError(
transform: (F) -> NewFailure
): Result<Nothing, NewFailure> = Failure(transform(reason))
override fun <NewSuccess> flatMap(
transform: (Nothing) -> Result<NewSuccess, F>
): Result<NewSuccess, F> = this
override fun <NewFailure : Throwable> flatMapError(
transform: (F) -> Result<Nothing, NewFailure>
): Result<Nothing, NewFailure> = transform(reason)
}
fun get(): S
fun <NewSuccess> map(transform: (S) -> NewSuccess): Result<NewSuccess, F>
fun <NewFailure: Throwable> mapError(transform: (F) -> NewFailure): Result<S, NewFailure>
fun <NewSuccess> flatMap(transform: (S) -> Result<NewSuccess, @UnsafeVariance F>): Result<NewSuccess, F>
fun <NewFailure: Throwable> flatMapError(
transform: (F) -> Result<@UnsafeVariance S, NewFailure>
): Result<S, NewFailure>
companion object {
inline operator fun <S> invoke(block: () -> S): Result<S, Throwable> = try {
val result = block()
Success(result)
} catch (e: Throwable) {
Failure(e)
}
fun <S> success(value: S): Result<S, Nothing> = Success(value)
fun <E: Throwable> failure(reason: E): Result<Nothing, E> = Failure(reason)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment