Skip to content

Instantly share code, notes, and snippets.

@bnorm
Last active October 4, 2017 23:56
Show Gist options
  • Save bnorm/0a17e053a551c22f4e56bb471e094747 to your computer and use it in GitHub Desktop.
Save bnorm/0a17e053a551c22f4e56bb471e094747 to your computer and use it in GitHub Desktop.
Try for Kotlin
sealed class Try<out T> {
companion object {
operator fun <T> invoke(f: () -> T) = try {
Success(f())
} catch (t: Throwable) {
Failure(t)
}
@JvmStatic
fun <T> success(value: T) = Success(value)
@JvmStatic
fun failure(exception: Throwable) = Failure(exception)
}
abstract val isSuccess: Boolean
abstract val isFailure: Boolean
operator abstract fun component1(): Throwable?
operator abstract fun component2(): T?
abstract fun get(): T
abstract fun forEach(f: (T) -> Unit)
abstract fun <U> map(f: (T) -> U): Try<U>
abstract fun <U> flatMap(f: (T) -> Try<U>): Try<U>
abstract fun <U> fold(handle: (Throwable) -> U, map: (T) -> U): U
abstract fun <U> flatFold(handle: (Throwable) -> Try<U>, map: (T) -> Try<U>): Try<U>
class Success<out T>(val value: T) : Try<T>() {
override val isSuccess = true
override val isFailure = false
operator override fun component1() = null
operator override fun component2() = value
override fun get() = value
override fun forEach(f: (T) -> Unit) = f(value)
override fun <U> map(f: (T) -> U) = try {
Success(f(value))
} catch (t: Throwable) {
Failure(t)
}
override fun <U> flatMap(f: (T) -> Try<U>) = try {
f(value)
} catch (t: Throwable) {
Failure(t)
}
override fun <U> fold(handle: (Throwable) -> U, map: (T) -> U) = try {
map(value)
} catch (t: Throwable) {
handle(t)
}
override fun <U> flatFold(handle: (Throwable) -> Try<U>, map: (T) -> Try<U>) = try {
map(value)
} catch (t: Throwable) {
handle(t)
}
override fun toString() = "Success($value)"
override fun equals(other: Any?) = this === other || (other is Success<*> && value == other.value)
override fun hashCode() = if (value != null) value.hashCode() else 0
}
class Failure(val exception: Throwable) : Try<Nothing>() {
override val isSuccess = false
override val isFailure = true
operator override fun component1() = exception
operator override fun component2() = null
override fun get() = throw exception
override fun forEach(f: (Nothing) -> Unit) {}
override fun <U> map(f: (Nothing) -> U) = this
override fun <U> flatMap(f: (Nothing) -> Try<U>) = this
override fun <U> fold(handle: (Throwable) -> U, map: (Nothing) -> U) = handle(exception)
override fun <U> flatFold(handle: (Throwable) -> Try<U>, map: (Nothing) -> Try<U>) = handle(exception)
override fun toString() = "Failure($exception)"
override fun equals(other: Any?) = this === other || (other is Failure && exception == other.exception)
override fun hashCode() = exception.hashCode()
}
}
operator fun <T> Try<T>.iterator(): Iterator<T> = when (this) {
is Try.Success -> listOf(value)
is Try.Failure -> emptyList()
}.iterator()
fun <T> Try<T>.orElse(other: T): T = when (this) {
is Try.Success -> value
is Try.Failure -> other
}
fun <T> Try<T>.orElseGet(f: () -> T): T = when (this) {
is Try.Success -> value
is Try.Failure -> f()
}
fun <T> Try<T>.handle(f: (Throwable) -> T): Try<T> = when (this) {
is Try.Success -> this
is Try.Failure -> Try { f(exception) }
}
fun <T> Try<T>.flatHandle(f: (Throwable) -> Try<T>): Try<T> = when (this) {
is Try.Success -> this
is Try.Failure -> try {
f(exception)
} catch (t: Throwable) {
Try.Failure(t)
}
}
fun <T> Try<Try<T>>.flatten(): Try<T> = when (this) {
is Try.Success -> value
is Try.Failure -> this
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment