I’m posting here because I’m not sure where I should post such bug report concerning the kotlinx support library. Please direct me to the proper bug tracker and I’ll be sure to post it there.
In the meantime, the bug being a pernicious one, it may be useful to warn other developpers
This code does not close the resource:
class Ressource() : AutoCloseable {
override fun close() {
println("Closing")
}
}
fun test(): String {
Ressource().use {
return "Hello, world!"
}
}
fun main(args: Array<String>) {
println(test())
}
When running this code, “Hello, world!” is printed but never “Closing”.
If I replace the test function by this, it works (note the difference in the placement of return
):
fun test(): String {
return Ressource().use {
"Hello, world!"
}
}
This is because of the way the use
function is declared in the kotlinx.support
library:
public inline fun <T : AutoCloseable, R> T.use(block: (T) -> R): R {
val result = try {
block(this)
} catch (e: Throwable) {
closeSuppressed(e)
throw e
}
close()
return result
}
Because it is an inline function, non-local returns are allowed in the “block” lambda. In case of such a return, the close code will never be executed.
The kotlin-stdlib
uses a try-finally
construct that ensure that, even in the case of a non-local return, the resource will be properly closed.
In my opinion, this is a very critical bug, because:
- it enables the possibility of exiting the
use
block without closing the resource, which is precisely whatuse
is supposed to prevent. - It behaves differently than the
kotlin-stdlib
version ofCloseable.use
. - It took me two hours to debug