3
votes

In the code below I have to return the result of a future that is invoked after another future. I'm getting the following error in the future2.map line:

type mismatch; found : scala.concurrent.Future[play.api.mvc.Result] required: play.api.mvc.Result

How to make this work?

def method1 = Action.async { request => 
    val future1 = f1
    future1.map { result1 =>
          val future2 = f2
          future2.map { result2 =>
              Ok(result1+result2+"")
          }
    }
}

def f1 = Future { 1 }
def f2 = Future { 2 }
2

2 Answers

5
votes

You could do this in many ways. But first, you need to understand how map and flatMap work with Future:

def map[S](f: (T) ⇒ S): Future[S]
def map[S](f: (T) ⇒ Future[S]): Future[Future[S]]
def flatMap[S](f: (T) ⇒ Future[S]): Future[S]

Note that,in above signatures, you are calling map and flatMap with a value that already is a future i.e Future[<some-value>].map(...) or Future[<some-value>].flatMap(...).

Approach 1:

    def method1 = Action.async { request =>
    val future1 = f1
    future1.flatMap { result1 => //replaced map with flatMap
      val future2 = f2
      future2.map { result2 =>
        Ok(result1+result2+"")
      }
    }
  }

  def f1 = Future { 1 }
  def f2 = Future { 2 }

Approach 2:

def method1 = Action.async { request =>
    val future1 = f1
    future1.flatMap { result1 => //replaced map with flatMap
      val future2 = f2
      future2.flatMap { result2 => //replaced map with flatMap
        Future.successful{Ok(result1+result2+"")} // used Future.successful{} to generate a Future of Result
      }
    }
  }

  def f1 = Future { 1 }
  def f2 = Future { 2 }
3
votes

Changing future1.map to future1.flatMap should do the trick. Mapping over a Future returns another Future and changes the value inside. In this case, you're returning a Future that contains another Future that contains a Result. By using flatMap, it essentially flattens the nested Future[Future[Result]] into a Future[Result].