scalascala-2.9

for comprehension from flatMap and future to future


I would like something like runProgram2 but currently that part does not compile. Is there a way to write it somewhat like runProgram2 but so it compiles..

package transformer

import scala.concurrent.{ExecutionContext, Promise, Future}
import ExecutionContext.Implicits.global
import java.util.concurrent.TimeUnit
import scala.concurrent.duration.Duration

object TestingForComprehensions2 {

    def main(args: Array[String]) = {
      val future1: Future[String] = runMyProgram()
      future1.onSuccess {
        case r:String =>       System.out.println("result="+r)
      }


      val future2: Future[String] = runMyProgram2()
      future2.onSuccess {
        case r:String =>       System.out.println("result="+r)
      }

      System.out.println("waiting")
      Thread.sleep(600000)
    }

    def runMyProgram() : Future[String] = {
      val future = serviceCall()
      val middle = serviceCallWrap(future)
      val future2 = middle.flatMap(serviceCall2)
      val future3 = future2.map(processAllReturnCodes)
      future3
    }

    def runMyProgram2() : Future[String] = {
      for {
        result1 <- serviceCall()
        middle = serviceCallWrap(result1)
        result2 <-  serviceCall2(middle)
      } yield processAllReturnCodes(result2)
    }

    def processAllReturnCodes(theMsg: String) : String = {
      "dean"+theMsg
    }

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

    def serviceCallWrap(f:Future[Int]) : Future[Int] = {
      f
    }

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

}

Solution

  • serviceCallWrap expects a future, but you are passing an Int, first step would be to remove the result1 <- serviceCall() part and call directly middle = serviceCallWrap(serviceCall()).

    Now middle is a future but serviceCall2 takes an Int, in this case you can extract the value from the future using middle <- serviceCallWrap(serviceCall()), all together:

    def runMyProgram2() : Future[String] = {
      for {
        middle <- serviceCallWrap(serviceCall())
        result2 <-  serviceCall2(middle)
      } yield processAllReturnCodes(result2)
    }
    

    If you want to keep the comprehension structure:

    def runMyProgram2() : Future[String] = {
      for {
        result1 <- serviceCall()
        middle <- serviceCallWrap(Future(result1))
        result2 <-  serviceCall2(middle)
      } yield processAllReturnCodes(result2)
    }
    

    The only thing you can't keep (AFAIK) is the assignment expression for middle, if you want to keep that you need to change serviceCall2 signature. This approach though has exactly the same result as the first approach, it's only more verbose.