Dean Hiller
Dean Hiller

Reputation: 20182

for comprehension with futures in scala translation to flatMap

I have been looking at this How are Scala Futures chained together with flatMap? and the corresponding article as well on translating for comprehension. I am slowly adding stuff to my for comprehension and am stuck as I guess the code I thought would translate to is not correct.

Here I have a runProgram and runProgram2 which I thought would be equivalent and are not because runProgram2 does not compile. Can someone explain the equiavalent of this for comprehension...

NOTE: yes I know that future.flatMap is typically for collapsing Future[Future[String]] but this is a trimmed down version of my file(perhaps I trimmed it down too far).

def main(args: Array[String]) = {
  val future1: Future[String] = runMyProgram()

  //val future2: Future[String] = runMyProgram2()

}

def runMyProgram() : Future[String] = {
  val future = serviceCall()
  future.flatMap(processAllReturnCodes)
}

//    def runMyProgram2() : Future[String] = {
//      val future = serviceCall()
//      for {
//        result <-  future
//      } yield processAllReturnCodes(result)
//    }

def processAllReturnCodes(count: Int) : Future[String] = {

  val promise = Promise.successful("done")
  promise.future
}

def serviceCall() : Future[Int] = {
  val promise = Promise.successful(5)
  promise.future
}

def serviceCall2() : Future[String] = {
  val promise = Promise.successful("hithere")
  promise.future
}

Upvotes: 0

Views: 352

Answers (1)

Ende Neu
Ende Neu

Reputation: 15773

This for comprehension:

for {
  result <-  future
} yield processAllReturnCodes(result)

Is being translated to this:

val t: Future[Future[String]] = future.map(result => processAllReturnCodes(result))

Comprehension is really only syntactic sugar for map and flatMap, with flatMap you can flatten the future nesting:

val u: Future[String] = future.flatMap(result => processAllReturnCodes(result))

The difference lies in the signatures:

def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S]

So map takes a function form T to S and wraps the S in a future, the problem is that here your S is a Future[String] which is wrapped in another future giving Future[Future[String]], flatMap instead:

 def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S]

Takes a function from T to Future[S] and returns that future, in your case your method already returns a future and it's a valid parameter for flatMap.

Upvotes: 2

Related Questions