Skip to content

Instantly share code, notes, and snippets.

@lanceon
Forked from jnape/FutureEither.scala
Created July 4, 2017 17:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lanceon/0ffed071a0a9f644d135496a67b99a15 to your computer and use it in GitHub Desktop.
Save lanceon/0ffed071a0a9f644d135496a67b99a15 to your computer and use it in GitHub Desktop.
Making dealing with Future[Either[L, R]] palatable in Scala
package com.thoughtworks.futureeither
import concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import concurrent.duration.FiniteDuration
import java.util.concurrent.TimeUnit
class FutureEither[L, R](private val future: Future[Either[L, R]]) {
def flatMap[R2](block: R => FutureEither[L, R2]): FutureEither[L, R2] = {
val result = future.flatMap {
case Right(r) => block.apply(r).future
case Left(l) => Future.successful(Left(l))
}
new FutureEither(result)
}
def map[R2](block: R => R2): FutureEither[L, R2] = {
val result = future.map {
case Right(r) => Right(block.apply(r))
case Left(l) => Left(l)
}
new FutureEither(result)
}
def recover(block: PartialFunction[L, R]): Future[R] = {
future.map {
case Right(r) => r
case Left(left) => block.apply(left)
}
}
}
object FutureEither {
//bidirectional implicit conversions between Future[Either[L, R]] and FutureEither[L, R]
}
object Example {
abstract sealed class Error {}
case class HeadFellOff() extends Error {}
case class PantsFellOff() extends Error {}
case class WTF() extends Error {}
def returnString: FutureEither[Error, String] = new FutureEither(Future(Right("a string!")))
def takeStringAndReturnInt(string: String): FutureEither[Error, Int] = new FutureEither(Future(Right(10)))
def takeIntAndReturnString(int: Int): FutureEither[Error, String] = new FutureEither(Future(Right("ftw")))
def main(args: Array[String]) {
val result = returnString.flatMap(
takeStringAndReturnInt(_).flatMap(
takeIntAndReturnString(_).map(_.toUpperCase)
)
).recover {
case HeadFellOff() => "head fell off!"
case PantsFellOff() => "pants fell off!"
case unanticipated => s"$unanticipated"
}
println(Await.result(result, FiniteDuration(5, TimeUnit.SECONDS)))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment