The Closeable interface in Java provides a convenient abstraction that facilitates the management of resources that can be closed. In the context of multi-platform kotlin, is there a pattern, practice or feature that can help breach the gap between a shared/multi-platform Closeable interface and the actual Java Closeable interface knowing that these are necessarily two different types?
The effects of not being able to close the type difference and/or having a standard-lib closeable are the proliferation of Closeable interfaces that can't be combined across libraries even though they are fundamentally the same thing.
This is already done for you in kotlinx-io library from the Kotlin team.
https://github.com/Kotlin/kotlinx-io
For Closeable
you should use that library directly, no need to create your own.
But if you want to create your own similar cross-platform abstraction, this acts as a nice sample. Here is what it is doing underneath the covers...
The common implementation which actually does the logic of closing and just expects each platform to have the interface available: (source)
expect interface Closeable {
fun close()
}
inline fun <C : Closeable, R> C.use(block: (C) -> R): R {
try {
val result = block(this)
close()
return result
} catch (first: Throwable) {
try {
close()
} catch (second: Throwable) {
first.addSuppressedInternal(second)
}
throw first
}
}
@PublishedApi
internal expect fun Throwable.addSuppressedInternal(other: Throwable)
The JVM version is just a simple type alias that matches the expected interface meaning that it is compatible with existing code, and implementation of suppressing the inner exception. (source)
actual typealias Closeable = java.io.Closeable
@PublishedApi
internal actual fun Throwable.addSuppressedInternal(other: Throwable) {
AddSuppressedMethod?.invoke(this, other)
}
private val AddSuppressedMethod: Method? by lazy {
try {
Throwable::class.java.getMethod("addSuppressed", Throwable::class.java)
} catch (t: Throwable) {
null
}
}
And the JS version is a new interface: (source)
actual interface Closeable {
actual fun close()
}
@PublishedApi
internal actual fun Throwable.addSuppressedInternal(other: Throwable) {
}
For native it is similar to JS, and so on for each platform...