Last active
August 16, 2018 23:34
-
-
Save roschlau/c667e1e81e80ecd6fec46769c3f953b5 to your computer and use it in GitHub Desktop.
Implementing the defer, panic and recover functions from golang in Kotlin, because reasons. I have hardly any knowledge of Go, I googled a little bit about how those functions work. The example is copied from https://blog.golang.org/defer-panic-and-recover and results in exactly the same output.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Optional | |
// Actual implementation | |
fun <T> deferringScope(block: DeferringScope<T>.() -> T): Optional<T> { | |
val scope = DeferringScope<T>() | |
try { | |
scope.result = Optional.of(scope.block()) | |
} catch (e: Throwable) { | |
scope.error = e.message ?: e.toString() | |
} | |
val state = scope.exit() | |
return when(state) { | |
is ExitState.Normal<T> -> state.result | |
is ExitState.Panicked<T> -> throw Exception(state.error) | |
} | |
} | |
class DeferringScope<T> { | |
var result: Optional<T> = Optional.empty() | |
var error: String? = null | |
private val deferred = mutableListOf<DeferringScope<T>.() -> Unit>() | |
fun defer(block: DeferringScope<T>.() -> Unit) { | |
deferred.add(0, block) | |
} | |
fun panic(reason: String? = null) { | |
throw Exception(reason) | |
} | |
fun recover() = error.also { error = null } | |
fun exit(): ExitState<T> { | |
deferred.forEach { it() } | |
error?.let { error -> | |
return ExitState.Panicked(error) | |
} | |
return ExitState.Normal(result) | |
} | |
} | |
sealed class ExitState<T> { | |
class Normal<T>(val result: Optional<T>) : ExitState<T>() | |
class Panicked<T>(val error: String) : ExitState<T>() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Optional | |
// Example usage, ported 1:1 from the last example in this blog: https://blog.golang.org/defer-panic-and-recover | |
fun main(args: Array<String>) { deferringScope<Unit> { | |
f() | |
println("Returned normally from f.") | |
}} | |
fun f() = deferringScope<Unit> { | |
defer { | |
recover()?.let { r -> | |
println("Recovered in f $r") | |
} | |
} | |
println("Calling g.") | |
g(0) | |
println("Returned normally from g.") | |
} | |
fun g(i: Int): Optional<Unit> = deferringScope { | |
if(i > 3) { | |
println("Panicking!") | |
panic(i.toString()) | |
} | |
defer { println("Defer in g $i") } | |
println("Printing in g $i") | |
g(i + 1) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment