I currently face the problem of correctly closing resources that never leave their containing Either
.
The relevant code looks something like this:
object SomeError
class MyRes : AutoCloseable { [...] }
fun createRes(): Either<SomeError, MyRes> { [...] }
fun extractData(res: MyRes): String { [...] }
fun theProblem(): Either<SomeError, String> {
return createRes()
.map { extractData(it) }
}
What is the most idiomatic way of closing the created MyRes
? Closing it before that map
prevents extractData
from accessing it, and after the map
I can't access it anymore via Either
's operations. Closing it in extractData
severely limits composability.
Currently I have an external List<AutoCloseable>
that I iterate over after all the computations, but that can't be the intended way.
I am open to using Arrow Fx (e.g. Resource
) if that helps, but I haven't found anything on how to combine Either
and Resource
in an elegant way.
CodePudding user response:
It's possible to combine the either
and Resource
safely.
object SomeError
class MyRes : AutoCloseable { [...] }
fun createRes(): Resource<Either<SomeError, MyRes>> { [...] }
fun extractData(res: MyRes): String { [...] }
suspend fun solution(): Either<SomeError, String> = either {
createRes().use { either: Either<SomeError, MyRes> ->
val res = either.bind()
val string = extractData(res)
// call other Either code `bind()` safely here
[...]
} // <-- MyRes will automatically close here
}
If in this code you encounter Either.Left
and you call bind()
on it the Resource
will first close, because we jump outside of use, and then either
will return the encountered Either.Left
.
CodePudding user response:
One possible solution I found was wrapping the block passed to map
:
fun <B : AutoCloseable, C> andClose(f: (B) -> C): (B) -> C =
{ b: B -> b.use { f(b) } }
fun theProblemSlightlySolved(): Either<SomeError, String> {
return createRes()
.map(andClose { extractData(it) })
}