Convert Future instances to cats-effect IO
Much (most?) of the third-parties software that you will have to deal with will not handle asynchronous actions using our beloved IO
monad, they will instead use either Scala’s or Java’s Future
. This brief entry shows how to convert those Future
s into IO
instances.
Scala
Future
toIO
: actually this is pretty straightforward, just useIO.fromFuture
:import cats.effect.IO import scala.concurrent.IO IO.fromFuture( IO(Future.successful("Scala Future converted to CE IO successfully")) )
Java
CompletableFuture
toIO
: as easy as runningIO.fromCompletableFuture
:import cats.effect.IO import java.util.concurrent.CompletableFuture IO.fromCompletableFuture( IO(CompletableFuture.completedFuture("Java CompletableFuture converted to CE IO successfully")) )
Java
Future
toIO
, this is unfortunately more convoluted. There is no a straightforward method to do this. Instead we will create a new method that periodically checks if theFuture
instance is completed and if so it returns its value, otherwise it sleeps (waits) and retries again. Note that the sleep call only blocks the fiber 'semantically', that is, the actual thread is not blocked. So this is a cheap method to execute. This method is a simplified version of this gist from Gavin Bisesi (Daenyth), which I encourage you to take a look. This is how we can define and use the method:import cats.effect.IO import java.util.concurrent.{CompletableFuture, Future => JFuture} // Convert a Java Future into an IO def convertToIO[A](fa: => JFuture[A]): IO[A] = IO.delay(fa.isDone).flatMap: isDone => if (isDone) IO.delay(fa.get) // Future done, return the result else IO.sleep(5.milliseconds) >> convertToIO(fa) // Retry again in a little while // Dummy creation of a dummy Java Future val createJavaFuture: IO[JFuture[String]] = IO{ val cf = new CompletableFuture[String]() cf.complete("Java Future converted to CE IO successfully") cf } createJavaFuture >>= convertToIO
So, that's all!
All code in this blog entry can be found in this gist. You can run it using scala-cli
:
$ scala-cli FutureToIO.scala
Or by invoking the gist itself from scala-cli
:
$ scala-cli https://gist.github.com/lrodero/4ae172a75b8a8d5bf72cba1890e3ac5f
Subscribe to my newsletter
Read articles from Luis Rodero-Merino directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Luis Rodero-Merino
Luis Rodero-Merino
Dev interested in functional programming solutions for Scala.