Future[Either] with Cats
Disclaimer Monad transformers have some overhead, so make sure you benchmark before and after switching to them
In a previous post I was exploring the use of the EitherT to make it easier to work with Either when it is nested in a Future. I’m currently reading the book Advanced Scala with Cats and decided to rewrite some of my code using the Cats library instead.
There’s also a page on Herding Cats where Eugene Yokota covers the same ground. I wanted to expand my examples from last post so that they actually execute in a Future so I can map that to my own error handling code in real programs. For example in the Herding Cats blog the demonstration code returns values like this:
EitherT.right(Future { List(User(1, "Michael")) })
What I wanted to figure out was how this looks in real code where you may have a function that works with a Future[Either]. I went back to my code from last post and modified the dummy functions so that:
- The code executes in a Future
- The function returns Cats EitherT type response
This makes things easier at the call site because instead of converting the response from Future[Either[String, A]] as I did then, you can simply use the EitherT directly. So instead of:
val r: FutureEither[String, Int] = for (
rb1 <- FutureEither(dummyFunction1(8));
rb2 <- FutureEither(dummyFunction1(12))
) yield rb1 + rb2
you can use the results directly
{for (
rb1 <- dummyFunction1(8);
rb2 <- dummyFunction1(12)
) yield (rb1 + rb2)}
If you check the example below the only thing needed to make your function return an EitherT[Future] is to use the EitherT constructor on the final value
EitherT[Future, String, Int](f)
The other thing you need to know about EitherT in Cats is that you need to use ‘value’ instead of ‘run’ to get into the results at the end.
I found this post useful for more ways to create a Future[Either] stack.
Final thoughts; whilst the the syntax is slightly different when working with EitherT and Cats, Scalaz and the Hamsters library, the concept is the same and it comes down to finding a way to use them that makes them easier to work with at the calling site. I think I can make things even cleaner with an implicit conversion from Future[Either] to EitherT[Future, String, A] but that will be possibly a later post.
Libraries used
Again for reference the libraries used when writing this post are as follow:
"org.typelevel" %% "cats" % "0.9.0"