2

I want to create a list of Future, each of which could pass or fail and collate results from successful Future. How can I do this?

val futures2:List[Future[Int]] = List(Future{1}, Future{2},Future{throw new Exception("error")})

Questions 1) I want to wait for each future to finish 2) I want to collect sum of return values from each success future and ignore the ones which failed (so I should get 3).

Manu Chadha
  • 15,555
  • 19
  • 91
  • 184
  • do you know how many futures you'll have to deal with before hand? – 0x6C38 Dec 29 '16 at 21:10
  • No but I am happy to assume a limited size. However, I want the solution to use List[Future] and not individual vals like f1, f2 – Manu Chadha Dec 29 '16 at 21:17
  • 1
    Sounds like a duplicate of: http://stackoverflow.com/questions/20874186/scala-listfuture-to-futurelist-disregarding-failed-futures?rq=1 – Michael Zajac Dec 29 '16 at 21:18
  • 3
    Something like: `Future.sequence(futures2.map(_.recover{case NonFatal(e) => 0})).map(_.sum)`... – insan-e Dec 29 '16 at 21:18
  • yes, it is a duplicate. Thanks for the reference. I cannot see the link to mark this question as duplicate. – Manu Chadha Dec 30 '16 at 08:38

1 Answers1

3

One thing that you need to understand is that... Avoid trying to "get" values from a Future or Futures.

You can keep on operating in the Futuristic land.

val futureList = List(
  Future(1),
  Future(2),
  Future(throw new Exception("error"))
)

// addd 1 to futures
// map will propagate errors to transformed futures
// only successful futures will result in +1, rest will stay with errors
val tranformedFutureList = futureList
  .map(future => future.map(i => i + 1))

// print values of futures
// simimlar to map... for each will work only with successful futures
val unitFutureList = futureList
  .map(future => future.foreach(i => println(i)))

// now lets give you sum of your "future" values
val sumFuture = futureList
  .foldLeft(Future(0))((facc, f) => f.onComplete({
    case Success(i) => facc.map(acc => acc + i)
    case Failure(ex) => facc
  })

And since OP (@Manu Chanda) asked about "getting" a value from a Promise, I am adding some bits about what Promise are in Scala.

So... first lets talk how to think about a Future in Scala.

If you see a Future[Int] then try to think of it as an ongoing computation which is "supposed to produce" an Int. Now that computation can successfully complete and result in a Success[Int] or a throw an exception and result in a Failure[Throwable]. And thus you see the functions such as onComplete, recoverWith, onFailure which seem like talking about a computation.

val intFuture = Future {
  // all this inside Future {} is going to run in some other thread
  val i = 5;
  val j = i + 10;
  val k = j / 5;
  k
}

Now... what is a Promise.

Well... as the name indicates... a Promise[Int] is a promise of an Int value... nothing more.

Just like when a parent promises a certain toy to their child. Note that in this case... the parent has not necessarily started working on getting that toy, they have just promised that they will.

To complete the promise... they will first have to start working to complete it... got to market... buy from shop... come back home.Or... sometimes... they are busy so... they will ask someone else to bring that toy and keep doing their work... that other guy will try to bring that toy to parent (he may fail to buy it) and then they will complete the promise with whatever result they got from him.

So... basically a Promise wraps a Future inside of it. And that "wrapped" Future "value" can be considered as the value of the Promise.

so...

println("Well... The program wants an 'Int' toy")

// we "promised" our program that we will give it that int "toy"
val intPromise = Promise[Int]()

// now we can just move on with or life
println("Well... We just promised an 'Int' toy")

// while the program can make plans with how will it play with that "future toy"

val intFuture = intPromise.future
val plusOneIntFuture = intFuture.map(i => i + 1)

plusOneIntFuture.onComplete({
  case Success(i) => println("Wow... I got the toy and modified it to - " + i)
  case Failure(ex) => println("I did not get they toy")
})

// but since we at least want to try to complete our promise
println("Now... I suppose we need to get that 'Int' toy")
println("But... I am busy... I can not stop everything else for that toy")
println("ok... lets ask another thread to get that")

val getThatIntFuture = Future {
  println("Well... I am thread 2... trying to get the int")
  val i = 1
  println("Well... I am thread 2... lets just return this i = 1 thingy")
  i
}

// now lets complete our promise with whatever we will get from this other thread
getThatIntFuture.onComplete(intTry => intPromise.complete(intTry))

The above code will result in following output,

Well... The program wants an 'Int' toy
Well... We just promised an 'Int' toy
Now... I suppose we need to get that 'Int' toy
But... I am busy... I can not stop everything else for that toy
Well... I am thread 2... trying to get the int
Well... I am thread 2... lets just return this i = 1 thingy
Wow... I got the toy and modified it to - 2

Promise don't help you in "getting" a value from a Future. Asynchronous processes (or Future in Scala) are just running in another timeline... you can not "get" their "value" in your time-line unless you work on aligning your timeline with the process's time-line itself.

sarveshseri
  • 13,738
  • 28
  • 47