Home > Back-end >  Closing (Auto)Closeables that exist only in `Either`
Closing (Auto)Closeables that exist only in `Either`

Time:04-29

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) })
}
  • Related