Returning two Scala futures when both end - scala

The method1 below is an attempt to return the results of two Future methods someFutureMethod1 and someFutureMethod2 combined. Any ideas how to make this work? Ideally the method that ends first should wait until the second ends, and then return the future values combined.
def method1 ( s: Seq[Int]): Future [(Int,Int)] = {
s.map { sx =>
val future = someFutureMethod1 (sx)
future.map {
result => result
}
val future2 = someFutureMethod2 (sx)
future2.map {
result2 => result2
}
(result,result2) // <-- the method should return the two results in the future
}
}
def someFutureMethod1 (i: Int) = Future {
i + 1
}
def someFutureMethod2 (i: Int) = Future {
i + 2
}

You combine Future's in a map, so it looks like you have to return a Seq of such Future's:
def method1 ( s: Seq[Int]): Seq[Future [(Int,Int)]] =
s.map { sx =>
val future = someFutureMethod1 (sx)
val future2 = someFutureMethod2 (sx)
future.zip(future2)
}

Related

How to resolve a Future inside another Future

I want to create a function similar to the following. Basically the function, say F will create a Future say fut1. When fut1 resolves, then another Future say fut2 should get created inside fut1. The fut2 should return the final value of the function F. The code has to be non-blocking all the way. I have written something like this but the return type is not Future[Int] but Future[Future[Int]]. I understand why this is the case (because map creates a Future) but I am unable to figure out how to return Future[Int] from this code.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def fut:Future[Int] = {
val f1 = Future{ 1 } //create a Future
f1.map (x => { //when f1 finishes, create another future
println(x)
val f2 = Future{ 2 }
f2.map(x=> x) //this creates another Future and thus the return is Future[Future[Int]]
})
}
You can achieve this using flat map or for comprehension.
FlatMap-
def futureFunctionWithFlatMap: Future[Int] = {
val f1 = Future {
1
}
f1.flatMap(x => {
println(x)
val f2 = Future {
2
}
f2.map(x => x)
})
}
For Comprehension
def futureFunctionWithForComprehension: Future[Int] = {
for {
f1 <- Future { 1 }
f2 <- {
println(f1)
Future { 2 }
}
} yield f2
}
Use flatMap
val f1 = Future{ 1 } //create a Future
val f2: Future[Int] = f1.flatMap(x => {
//will be triggered only after x is ready
Future{2}
})

replace a while loop with Future in scala

I have a function with return value of Future[Int]
def func: Future[Int] = {...}
I will periodically check the return value of func until it meet some condition(e.g. return value greater than 10), then I will take use of this return value to create other future value with map/flatmap.
How can I make this work without any synchronous code? which is listed below:
def check: Future[Int] = {
var ret: Int = Await.result(func, Duration.Inf)
while (ret <= 10) {
ret = Await.result(func, Duration.Inf)
}
Future(ret + 100)
}
One way to achieve this is using recursion as shown below.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
def check(func: () => Future[Int]): Future[Int] = {
Future.unit.flatMap(_ => func()) flatMap {
case x if x <= 10 => check(func)
case x => Future.successful(x + 100)
}
}

Match on tuples within for comprehension

I am trying to write a function that returns a future. Within this future 3 other future functions are called, the third depends on the results of the first two. My instinct is to use a for comphrension, but when I try to match on the tuple I get this error:
value map is not a member of Object
Which refers to the match of (result1, result2) below
def future1 = Future { ... }
def future2 = Future { ... }
def future3(a, b): Future[T] = Future { .... }
def future4: Future[T] = {
for {
result1 <- future1
result2 <- future2
result3 <- (result1, result2) match {
case (x, y) => future3(result1, result2)
case (_, _) => ???
}
} yield result3
}
It can be solved by making whatever is under ??? return Future[T]

Returning Future of Future in Play for Scala

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 }
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 }
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].

Sequentially combine arbitrary number of futures in Scala

I'm new to scala and I try to combine several Futures in scala 2.10RC3. The Futures should be executed in sequential order. In the document Scala SIP14 the method andThen is defined in order to execute Futures in sequential order. I used this method to combine several Futures (see example below). My expectation was that it prints 6 but actually the result is 0. What am I doing wrong here? I have two questions:
First, why is the result 0. Second, how can I combine several Futures, so that the execution of the second Future does not start before the first Future has been finished.
val intList = List(1, 2, 3)
val sumOfIntFuture = intList.foldLeft(Future { 0 }) {
case (future, i) => future andThen {
case Success(result) => result + i
case Failure(e) => println(e)
}
}
sumOfIntFuture onSuccess { case x => println(x) }
andThen is for side-effects. It allows you to specify some actions to do after future is completed and before it used for something else.
Use map:
scala> List(1, 2, 3).foldLeft(Future { 0 }) {
| case (future, i) => future map { _ + i }
| } onSuccess { case x => println(x) }
6
I like this generic approach:
trait FutureImplicits {
class SeriallyPimp[T, V](futures: Seq[T]) {
def serially(f: T => Future[V])(implicit ec: ExecutionContext): Future[Seq[V]] = {
val buf = ListBuffer.empty[V]
buf.sizeHint(futures.size)
futures.foldLeft(Future.successful(buf)) { (previousFuture, next) =>
for {
previousResults <- previousFuture
nextResult <- f(next)
} yield previousResults += nextResult
}
}
}
implicit def toSeriallyPimp[T, V](xs: Seq[T]): SeriallyPimp[T, V] =
new SeriallyPimp(xs)
}
Then mix-in the above trait and use it like this:
val elems: Seq[Elem] = ???
val save: Elem => Future[Result] = ???
val f: Future[Seq[Result]] = elems serially save
This code could be improved to preserve the input collection type. See this article for example.