Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining Scala Futures and collections in for comprehensions

Tags:

scala

I'm trying to use a for expression to iterate over a list, then do a transformation on each element using a utility that returns a Future. Long story short, it doesn't compile, and I'd like to understand why. I read this question, which is similar, and was a great help, but what I'm trying to do is even simpler, which is all the more confusing as to why it doesn't work. I'm trying to do something like:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val numberList = List(1, 2, 3)
def squareInTheFuture(number: Int): Future[Int] = Future { number * number}
val allTheSquares = for {
                          number <- numberList
                          square <- squareInTheFuture(number)
                        } yield { square }

And what I get is:

error: type mismatch; found : scala.concurrent.Future[Int] required: scala.collection.GenTraversableOnce[?] square <- squareInTheFuture(number) ^

Can someone help me understand why this doesn't work and what the best alternative is?

like image 637
Joe Avatar asked Nov 20 '13 22:11

Joe


People also ask

How do you handle Future Scala?

Handle the result of a future with methods like onComplete , or combinator methods like map , flatMap , filter , andThen , etc. The value in a Future is always an instance of one of the Try types: Success or Failure.

What is the difference between a Java Future and a Scala Future?

A Java Future works in a synchronous blocking way. It does not work in an asynchronous non-blocking way, whereas a Scala Future works in an asynchronous non-blocking way. If we want an asynchronous non-blocking feature, we should use Java 8's CompletableFuture.

Is Scala Future a thread?

Future. Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.

What is for comprehension in Scala?

Scala offers a lightweight notation for expressing sequence comprehensions. Comprehensions have the form for (enumerators) yield e , where enumerators refers to a semicolon-separated list of enumerators. An enumerator is either a generator which introduces new variables, or it is a filter.


2 Answers

The Future companion object has a traverse method that does exactly what you want:

val allTheSquares: Future[List[Int]] =
  Future.traverse(numberList)(squareInTheFuture)

This will asynchronously start all the computations and return a future that will be completed once all of those futures are completed.

like image 186
Travis Brown Avatar answered Nov 15 '22 10:11

Travis Brown


flatMap requires that the type constructors of numberList and squareInTheFuture(number) are the same (modulo whatever implicit conversions the collection library does). That isn't the case here. Instead, this is a traversal:

val allSquaresInTheFuture: Future[List[Int]] =
    Future.traverse(numberList)(squareInTheFuture)
like image 32
Ben James Avatar answered Nov 15 '22 11:11

Ben James