1

I have a function as follows:

def bar(x : Int) : Either[String, Future[Option[Foo]]] = {
  Goo() recover { case e => Left("Some error string") }
}

As you can see, if the Future fails then it will hit the partial function inside the recover body. This will return Left and satisfies the left part of the Either type. What I am stuck on is how to return the Right if the Goo future completes successfully.

I tried the following:

def bar(x : Int) : Either[String, Future[Option[Foo]]] = {
  Goo().map(x => Right(Future.successful(x))) recover { case e => Left("Some error string") }
}

However, I get a type error indicating that the return type for bar is Future[Either[String, Future[Foo]]].

How can I return a Right(x) where x is some value of type Foo?

UPDATE

def bar(x : Int) : Future[Either[String, Option[Foo]]] = {
  Goo().map(x => Right(x)) recover { case e => Left("Some error string") }
}
  • http://stackoverflow.com/questions/14168712/converting-akkas-futurea-to-futureeitherexception-a – dk14 Dec 22 '15 at 17:11
  • Btw, there is no way to get `Either` of `Future` without `Await` - you can get only `Future` of `Either` – dk14 Dec 22 '15 at 17:12
  • @dk14, please see the update. Changing the return type to Future[Either... now type checks and is actually what I want. –  Dec 22 '15 at 17:22
  • you probably don't need `Future.successful` over there – dk14 Dec 23 '15 at 11:53

1 Answers1

0

You didn't define Goo, but i'll assume for the moment the following:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

case class Foo(n: Int)

/** Takes a string and returns a future int-parsing of it */
def Goo(s: String): Future[Foo] = Future {
  Foo(java.lang.Integer.parseInt(s))  // will throw an exception on non-int
}

Then if you want bar(s: String) to return Either[String, Option[Foo]] where the Option is a Some[Foo] if the number is parseable and positive, or None if parseable but non-positive and the String is an explanation of why it failed to parse, you could do:

import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.util.control.NonFatal

def bar(s: String): Future[Either[String, Option[Foo]]] = {
  Goo(s).map { foo: Foo =>
    Right(if (foo.n > 0) Some(foo) else None)
  }.recover {
    case NonFatal(e) => Left("Failed to parse %s: %s".format(s, e))
  }
}

voila:

scala> Await.result(bar("4"), Duration.Inf)
res1: Either[String,Option[Foo]] = Right(Some(Foo(4)))

scala> Await.result(bar("-4"), Duration.Inf)
res2: Either[String,Option[Foo]] = Right(None)

scala> Await.result(bar("four"), Duration.Inf)
res3: Either[String,Option[Foo]] = Left(Failed to parse four: java.lang.NumberFormatException: For input string: "four")
Rob Starling
  • 3,868
  • 3
  • 23
  • 40
  • Go ahead and toss a `java.lang.Thread.sleep(2000)` as the first thing inside the `Future { ... }` of `Goo`'s definition to see actual delayed futures. – Rob Starling Dec 22 '15 at 19:14